【问题标题】:Accessing data in a Frame or Iframe with IE plugin Browser Helper Object (BHO)使用 IE 插件 Browser Helper Object (BHO) 访问 Frame 或 Iframe 中的数据
【发布时间】:2011-03-31 07:33:45
【问题描述】:

我正在编写一个 IE 插件,它将电话号码包装在一个链接中,该链接连接到电话系统并在单击时拨打该号码。我通过使用 DocumentComplete 事件来完成此操作。

//using SHDocVw.WebBrowser
webBrowser.DocumentComplete += new DWebBrowserEvents2_DocumentCompleteEventHandler(this.OnDocumentComplete);

问题是我似乎无法访问 frame 和 iframe 元素内的元素。

问题:如何使用 Browser Helper 对象在 IE 中处理 frame 和 iframe 元素内的数据?

【问题讨论】:

    标签: c# internet-explorer dom plugins bho


    【解决方案1】:

    首先,一些警告。一般来说,这种性质的附加组件(例如,在所有页面上运行并扫描所有内容的附加组件)会对性能产生重大影响,并且可能会导致用户在看到附加组件带来的性能影响时删除或禁用该附加组件。进一步看来,您是在 .NET 中编写代码,由于性能影响,强烈建议不要这样做。

    获取跨域子帧的内容并非易事,因为默认情况下您将获得拒绝访问。原因是 JavaScript 存在的跨域安全限制也会在您的插件尝试获取跨域内容时应用。

    要从顶级页面获取跨域内容,您必须跳过一些非常重要的环节,尤其是在 .NET 中。正如 Jeff 所观察到的,您最好的选择是只在每个帧的 DocumentComplete 事件上运行您的代码。

    如果您必须从顶级页面只运行一次代码,那么您可以使用以下技术来执行此操作:

    http://support.microsoft.com/default.aspx?scid=kb;en-us;196340

    // &lpDocDisp is the dispatch pointer for the document
    IHTMLDocument2* pDocument;
    HRESULT hr = lpDocDisp->QueryInterface(IID_IHTMLDocument2, (void**)&pDocument);
    if (FAILED(hr))
        return hr;
    
    long iCount = 0;
    
    // Now, check for subframes
    // http://support.microsoft.com/default.aspx?scid=kb;en-us;196340
    IOleContainer* pContainer;
    
    // Get the container
    hr = lpDocDisp->QueryInterface(IID_IOleContainer, (void**)&pContainer);
    if (FAILED(hr) || (NULL == pContainer)){
        OutputDebugString("[AXHUNTER] Failed to get container\n");
        return hr;
    }
    
    LPENUMUNKNOWN  pEnumerator;
    
    // Get an enumerator for the frames
    hr = pContainer->EnumObjects(OLECONTF_EMBEDDINGS, &pEnumerator);
    pContainer->Release();
    
    if (FAILED(hr) || (NULL == pEnumerator)){
        OutputDebugString("[AXHUNTER] Failed to get enumerator\n");                 
        return hr;
    }
    
    IUnknown* pUnk;
    ULONG uFetched;
    
    // Enumerate all the frames
    for (UINT i = 0; S_OK == pEnumerator->Next(1, &pUnk, &uFetched); i++)
    {
        assert(NULL != pUnk);
        IWebBrowser2* pBrowser;
        hr = pUnk->QueryInterface(IID_IWebBrowser2, (void**)&pBrowser);
        pUnk->Release();
    
        if (SUCCEEDED(hr))
        {
            LPDISPATCH pSubDoc = NULL;
            hr = pBrowser->get_Document(&pSubDoc);
            if (SUCCEEDED(hr) && (NULL != pSubDoc)){
                CrawlPage(pSubDoc, ++iNested);
                pSubDoc->Release();
            }
    
            pBrowser->Release();
        }
        else
        {
            OutputDebugString("[AXHUNTER] Cannot get IWebBrowser2 interface\n");
        }
    }
    
    
    pEnumerator->Release();
    

    【讨论】:

    【解决方案2】:

    您不能在框架内走动,但 DWebBrowserEvents2 应该为每个框架触发一个文档完成事件。您只需要跟踪所有这些。不确定如何转换为托管代码。

    根据您的要求,写一个Accelerator 会容易得多。它们只是 IE8+,但是...

    【讨论】:

    • 要求任何页面上的每个电话号码都必须是一个链接,并且可能在某处显示所有找到的电话号码。我认为加速器不可能做到这一点。我实际上更喜欢使用加速器,因为它可以确保使用它的每个人都升级到 IE8。
    【解决方案3】:

    在 iframe 中处理数据时,我能想到的唯一方法是给它一个查询字符串,或者您可以进行某种回发(也许是异步的?)。至于从该 iframe 中检索数据的方式相同。关于框架,据我所知,它们已被弃用,因此我建议您考虑更改它们。

    【讨论】:

      猜你喜欢
      • 2011-07-04
      • 2014-12-04
      • 1970-01-01
      • 2011-09-07
      • 1970-01-01
      • 2017-05-04
      • 1970-01-01
      • 1970-01-01
      • 2014-04-25
      相关资源
      最近更新 更多