刚刚结的那个帖子在这里:
http://topic.csdn.net/u/20080911/15/6cec0b2c-9574-4662-b41b-d5f6e685c065.html?seed=1848159299我发现的一个新问题是
现在的代码是设定一个自定义的接受消息的 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;            //取得表单域,并且点击按钮
            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;    
                            
            }

解决方案 »

  1.   

    我的意思是,相当做个给系统装个 callback 函数的功能,然后,我的程序作为一个类似后台驻留的程序,只要我的 exe 不退出,我就能收到我之前枚举过的(当然,也可以在中途添加枚举)我所关心的所有网页表单的消息(当然,这个消息是用户手工点击的,不是程序模拟点击的)不知道我把问题说明白了没有。
      

  2.   

    请确保点击的元素是你希望的元素,并且点击后确实执行了提交动作。
    类型为image的input元素往往不执行提交动作,你还不如寻找类型为submit的input元素。
      

  3.   


    呵呵,是这样的,我们公司正在搞一个能支持自动登录的插件,并且能帮助用户管理帐号信息。。所以,你看有些网站用的就是一个 image 类型的登录按钮嘛。。当然,不管是什么类型的,我必然是要能保证能收到表单提交的消息。我在上一个帖子里面就已经改了个自己的 invoke 用来接收消息了。所以不管是 submit的input元素,还是 image的input元素 ,我都是要关心的。所以,老大能指点一下,怎么做成后台驻留的不?
      

  4.   

    image按钮本身不能提交,但是可以执行脚本来调用submit.click()或者form.submit(),这是模拟提交的结果,但不管是哪种,你的onsubmit事件是肯定能收到的,如果收不到,只有一种可能情况,脚本中使用了onsubmit,并且终止了事件的继续传递。你可以看看网页的代码,看看image是如何提交的,应该是执行了脚本
      

  5.   


    额,估计版主还是没有看懂我的意思
    我现在确实是可以收到 onsubmit 的消息。。但是呢,我想做的功能是这样的,就是,用我原来的代码呢,因为是用连接点设定一个自定义的接受消息的 invoke,然后紧接着的代码就是模拟点击我感兴趣的页面元素提交表单。这样确实能收到。但是我想做的是,只用代码来设定一个 invoke用来接收事件,然后程序保持不退出。然后当用户用手工点击提交表单的时候,我之前设定的 invoke 能收到。但是现在的情况是,我把后面的提交表单的代码注释掉之后,设定的 invoke 就没反应了,是不是因为设定了 invoke 的 spFormElement 是个临时变量的问题?代码我发一份到版主邮箱([email protected])吧,代码很简单。有代码可能好沟通一些,先谢谢了。
      

  6.   

    put_onsubmit是可以实现的, 详见我在上个帖 子的结尾留言.
      

  7.   


    额,如果那样用的话,会报在  ULONG __stdcall Release(void) 的时候,内存错误。奇怪。
      

  8.   

    把delete this去掉... : )
      

  9.   

    恩,如果用 put_onsubmit 的话,得把 CComVariant vEvent; 也提到前面去作为全局变量才行。
      

  10.   


    把 CComVariant vEvent; 也提到前面去作为全局变量,就可以了但是,依然还是那样,如果我不注释掉 下面的 模拟点击 image 代码,就能进入我的 invoke 
    如果是用手工去点击,但是保持程序不退出,我的invoke 就收不到消息。是不是还有哪个变量应该要注意保存??
      

  11.   

    稍等,我调试下,可能需要在onsubmit属性变化前对onsubmit事件进行拦截, 也就是jameshooo说的:脚本中使用了onsubmit,并且终止了事件的继续传递。 
      

  12.   


    额,我倒是觉得,估计还是哪个变量要保存为全局变量的问题你想啊,我不注释掉下面的模拟点击的代码的话, 我的 invoke 是可以收到消息的。所以我怀疑是循环结束后,虽然我的程序还没有推出,但是一些变量就被销毁了。版主觉得有没有这个可能?
      

  13.   

    全局变量,new出来都是一样, 我怀疑是跨进程访问的问题,你的IHTMLDocument2不属于当前进程中,你
    可以写个测试例子,嵌入一个webbrowser在你自已的进程中,然后,看调不调用?
      

  14.   


    啊,我是说,
    我先,在上面hr = spFormElement->put_onsubmit( vEvent );然后,立即使用下面的代码立即点击,然后我的 invoke 是可以收到消息的。
                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;    
                                
                }但是我光 hr = spFormElement->put_onsubmit( vEvent );
    而把 hr = spSingleElement->click(); 给注释掉的话,然后我转到页面去手工点击,我的 invoke 就收不到消息了。不知道这回说清楚没有?
      

  15.   

    是这样的, 你程序化的点击是可以收到的,表明事件sink设置是没问题的, 但是手工点击不行, 按照, 我上面说的你嵌入一个webbrowser控件到你的程序进程中, 用同样方法调试下.
      

  16.   


    啊? 你的意思是不是说,程序点击确实可以收到,但是手工点击必然是收不到的?这是一种特性?
    不知道我理解错你的说法没有。
    那如果是这样,得想办法去 Hook 其他IE进程的函数了?
      

  17.   


    啊,先谢谢了,我想了下,
    应该是这个的问题
    ::CoInitialize(NULL); //初始化 COM 公寓 EnumIE(); //枚举浏览器 ::CoUninitialize(); //释放 COM 公寓
    看,当 EnumIE() 结束的时候 ,跟着就 CoUninitialize() 了,所以,我的程序虽然没有退出,但是 所有的COM对象 已经销毁了,所以不管是 new 出来的还是全局变量,都不起作用。。版主觉得呢?
      

  18.   

    应该是这个问题,另外,你的getchar()函数可能阻止消息发送,我修改你的debug版变成了winmain的工程,并用了你相同的代码,调试通过。
    源代码已发送到你邮箱。
      

  19.   

    设置好所有东西后,请保持一个消息循环的代码来维持运行,COM调用依赖于消息循环,否则你的事件方法肯定不会被调用到。