使用IE插件浏览器帮助程序对象(BHO)访问Frame或Iframe中的数据

时间:2010-08-18 01:29:16

标签: c# internet-explorer dom plugins bho

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

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

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

问题:如何使用浏览器助手对象操纵IE中框架和iframe元素内的数据?

3 个答案:

答案 0 :(得分:5)

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

获取跨域子帧的内容非常重要,因为默认情况下您将获得“拒绝访问”。原因是,当您的加载项尝试获取跨域内容时,也会应用JavaScript存在的跨域安全限制。

要从顶级页面获取跨域内容,您必须跳过一些非常重要的环节,特别是在.NET中。你最好的选择是在每个框架的DocumentComplete事件上运行你的代码,就像Jeff观察到的那样。

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

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();

答案 1 :(得分:1)

您无法在框架内行走,但DWebBrowserEvents2应为每个框架触发文档完成事件。你只需要跟踪它们。不确定如何转换为托管代码。

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

答案 2 :(得分:0)

在iframe中操作数据时,我能想到的唯一方法是给它一个查询字符串,或者你可以做一些回发(async也许?)。至于从iframe中检索数据将采用相同的方式。关于框架,我们不推荐使用它们,因此我建议您考虑更改它们。