none
获取网页框中的值,在线程中打印出来。 RRS feed

  • 问题

  • 功能:获取百度中间框中的值并且显示出来。

    代码:声明CComPtr<IHTMLInputTextElement> pPwdElement = NULL;全局变量在钩子中。#pragma data_seg("mydata")
         CComPtr<IHTMLInputTextElement> pPwdElement = NULL;
         #pragma data_seg()

    然后在钩子获取WM_LBUTTONDOWN的时候调用代码:

    void GetElement(IHTMLDocument2 *pDoc2,POINT pt)
    {
        if(pDoc2==NULL)
        {
            return;
        }
        CComPtr<IHTMLElement> pElement;
        HRESULT hr=pDoc2->elementFromPoint(pt.x,pt.y,&pElement);
        if(SUCCEEDED(hr)){
            //CComPtr<IHTMLInputTextElement> pPwdElement;
            hr=pElement->QueryInterface(IID_IHTMLInputTextElement,
                (void**)&pPwdElement);
            if(SUCCEEDED(hr))
            {
                ::AfxMessageBox("获取element成功");
            }
        }
    }

    然 后启用一个线程,线程中间调用代码:pPwdElement->get_value(&bStr);如果将接口只是放在钩子中使用是没有问 题的,如果想用线程将数据打印出来的时候。每次一调试到了这个地方。我看到pPwdElement不是NULL,但是每次都是内存冲突。直接运行就是报 错。高手指点下,如果要在线程中扑捉到网页中间输入框。然后输出它里面的值,我这种方法哪里错了,或者是否还有其他更好的方法。麻烦各位

    2012年7月15日 13:01

答案

  • IE的DOM对象,如你所使用的IHTMLInpuTTextElement,都是STA对象的。也就是说,哪个线程获得的,只能在哪个线程使用。要在不同进程中使用该接口,必须进行散列(Marshal)。使用CoMarshalInterface() (MSDN资料),然后在另外一个进程中,使用CoUnmarshalInterface(MSDN资料)还原(Unmarshal)。

    上述方法有些繁琐,建议使用GIT(Global Interface Table,全局接口表),见MSDN资料,或CSDN文章:用全局接口表实现COM接口在不同线程中的传递

    • 已标记为答案 Helen Zhao 2012年7月23日 6:07
    2012年7月16日 7:57
  • GlobalInterfaceTable它本身也是COM对象,它的指针不能在不同线程间传递。 所以每次都要实例化,我按照你的思路用了全局变量效果是一样的,我在想是不是

     pPwdElement.CoCreateInstance(CLSID_PSClassObject);这些代码有问题,找了许多资料,还是没能搞清楚。明日继续

    并不是所有的COM对象接口都不可以在线程中传递。是否可以传递,取决于COM对象的类型。比如,STA对象就不可以。我现在暂时没有找到官方的说明,但是,项目中通常都是使用全局的IGlobalInterfaceTable指针的。如果你觉得这样不好,我则建议你保留钩子里的IGlobalInterfaceTable,因为但你释放最后一个GIT引用时,可能会释放所有在GIT中注册的借口。

    我之前的说明,有一点不对。GIT在一个进程之中是唯一的。所以,你的使用所得到的GIT也是一样的。区别在于,如果在你的工作线程中使用GIT前,就释放了所有的GIT引用,可能会引起GIT清除所有的借口。

    • 已标记为答案 Helen Zhao 2012年7月23日 6:07
    2012年7月17日 18:00

全部回复

  • IE的DOM对象,如你所使用的IHTMLInpuTTextElement,都是STA对象的。也就是说,哪个线程获得的,只能在哪个线程使用。要在不同进程中使用该接口,必须进行散列(Marshal)。使用CoMarshalInterface() (MSDN资料),然后在另外一个进程中,使用CoUnmarshalInterface(MSDN资料)还原(Unmarshal)。

    上述方法有些繁琐,建议使用GIT(Global Interface Table,全局接口表),见MSDN资料,或CSDN文章:用全局接口表实现COM接口在不同线程中的传递

    • 已标记为答案 Helen Zhao 2012年7月23日 6:07
    2012年7月16日 7:57
  • 很感谢您给我的帮助,按照您的方法我写代码如下。m_dwCookie全局变量。

    钩子中:

    CComPtr<IHTMLInputTextElement> pPwdElement;
            pPwdElement.CoCreateInstance(CLSID_PSClassObject);
            CComPtr<IGlobalInterfaceTable> spGIT;
            spGIT.CoCreateInstance(CLSID_StdGlobalInterfaceTable);
            hr=pElement->QueryInterface(IID_IHTMLInputTextElement,
                (void**)&pPwdElement);
            if(spGIT)
            {
                spGIT->RegisterInterfaceInGlobal(pPwdElement,IID_IHTMLInputTextElement , &m_dwCookie);//IID_IHTMLInputTextElement
            }

    线程中调用:

    CComPtr<IHTMLInputTextElement> pxElement = NULL;
                            if(m_dwCookie != 0)
                            {
                                CComPtr<IGlobalInterfaceTable> spGIT;
                                spGIT.CoCreateInstance(CLSID_StdGlobalInterfaceTable);
                                if (spGIT)
                                {
                                    spGIT->GetInterfaceFromGlobal(m_dwCookie, IID_IHTMLInputTextElement, (void**)&pxElement.p);
                               
                                }
                                if(pxElement)
                                {
                                    CComBSTR pwd;
                                    pxElement->get_value(&pwd);
                                }
                            }

    搞了一晚上了,没搞好,获取到的pxElement总是0x000..空的,忧郁。因为时间关系,没时间仔细研究了。有经验的能不能直接告诉我哪个地方有问题。感谢

    2012年7月17日 1:16
  • 应该使用一个全局的IGlobalInterfaceTable,这样才能保证用同样的cookie取出同样的内容

    • 已建议为答案 Helen Zhao 2012年7月23日 6:07
    2012年7月17日 2:03
  • GlobalInterfaceTable它本身也是COM对象,它的指针不能在不同线程间传递。 所以每次都要实例化,我按照你的思路用了全局变量效果是一样的,我在想是不是

     pPwdElement.CoCreateInstance(CLSID_PSClassObject);这些代码有问题,找了许多资料,还是没能搞清楚。明日继续

    2012年7月17日 16:33
  • 为什么要使用

    pPwdElement.CoCreateInstance(CLSID_PSClassObject);

    这一句呢?

    2012年7月17日 16:40
  • GlobalInterfaceTable它本身也是COM对象,它的指针不能在不同线程间传递。 所以每次都要实例化,我按照你的思路用了全局变量效果是一样的,我在想是不是

     pPwdElement.CoCreateInstance(CLSID_PSClassObject);这些代码有问题,找了许多资料,还是没能搞清楚。明日继续

    并不是所有的COM对象接口都不可以在线程中传递。是否可以传递,取决于COM对象的类型。比如,STA对象就不可以。我现在暂时没有找到官方的说明,但是,项目中通常都是使用全局的IGlobalInterfaceTable指针的。如果你觉得这样不好,我则建议你保留钩子里的IGlobalInterfaceTable,因为但你释放最后一个GIT引用时,可能会释放所有在GIT中注册的借口。

    我之前的说明,有一点不对。GIT在一个进程之中是唯一的。所以,你的使用所得到的GIT也是一样的。区别在于,如果在你的工作线程中使用GIT前,就释放了所有的GIT引用,可能会引起GIT清除所有的借口。

    • 已标记为答案 Helen Zhao 2012年7月23日 6:07
    2012年7月17日 18:00