获取IE (控件)的所有链接(包括Frameset, iframe)

IE 顶层 body 节点通过IHTMLElement->get_all 方法无法获取iframe 里面的节点列表

CComPtr<IHTMLElement> body;
 
CComPtr<IDispatch> spDispCollection;
body->get_all(&spDispCollection);

所以要获取iframe/frame(frameset) 里面的节点列表的话, 则需要根据body/doc 找到frames, 然后从frames -> IHTMLWindow2 -> IHTMLDocument2 . 主要有2个方法, 下面是代码片段 
方法一:

IHTMLDocument2 *pDoc = 浏览器的Document(IWebBrowser2->IDispatch->IHTMLDocument2); 
IHTMLWindow2 *pHTMLWnd = NULL; 
IHTMLDocument2 *pFrameDoc=NULL; 
IHTMLFramesCollection2 *pFramesCollection=NULL; 
LPDISPATCH lpDispatch;

long p; 
VARIANT varindex,varresult; 
varresult.vt=VT_DISPATCH; 
varindex.vt = VT_I4; 
if(pDoc!=NULL) 

    HRESULT hr=pDoc->get_frames(&pFramesCollection); 
    if(SUCCEEDED(hr)&&pFramesCollection!=NULL) 
    { 
        hr=pFramesCollection->get_length(&p); 
        if(SUCCEEDED(hr)) 
            for(int i=0; i<p; i++) 
            { 
                varindex.lVal = i; 
                if(pFramesCollection->item(&varindex, &varresult) ==S_OK) 
                { 
                    lpDispatch=(LPDISPATCH)varresult.ppdispVal; 
                    if (SUCCEEDED(lpDispatch->QueryInterface(IID_IHTMLWindow2, (LPVOID *)&pHTMLWnd))) 
                    { 
                        if(SUCCEEDED(pHTMLWnd->get_document( &pFrameDoc))) 
                        { 
                            //work with the pFrameDoc 
                        } 
                        pHTMLWnd->Release(); 
                        pHTMLWnd=NULL; 
                    } 
                } 
            } 
            pFramesCollection->Release(); 
    } 
    pDoc->Release(); 
}

方法二:

CComQIPtr<IHTMLElement> pElem = ; // 可以递归上面的 CComPtr<IDispatch> spDispCollection 来得到 
CComBSTR bstrTagName;
pElem->get_tagName(&bstrTagName);
if ( lstrcmpiW(L"IFRAME", bstrTagName)==0 ||
        lstrcmpiW(L"FRAME", bstrTagName)==0 )
{
    CComQIPtr<IHTMLFrameBase2>    _framebase2;
    CComPtr<IHTMLWindow2>        _framewindow;
    CComPtr<IHTMLDocument2>        _framedoc;
    
    if( (_framebase2 = spItem) 
        && SUCCEEDED( _framebase2->get_contentWindow(&_framewindow) ) && _framewindow!=NULL 
        && SUCCEEDED( _framewindow->get_document(&_framedoc) ) && _framedoc!=NULL )
    {
        // 对 _framedoc 节点进行处理
    }
}

iframe 跨域访问(cross frame)  zz from : http://codecentrix.blogspot.com/2007/10/when-ihtmlwindow2getdocument-returns.html 
由于安全性限制, 为防止跨域脚本攻击, 当frames 跨域的时候, IHTMLWindow2::get_document 调用将返回 E_ACCESSDENIED . 
下面函数 HtmlWindowToHtmlDocument  对于跨域的frame 通过 IHTMLWindow2 -> IID_IWebBrowserApp -> IHTMLWindow2 绕过了限制.

// Converts a IHTMLWindow2 object to a IHTMLDocument2. Returns NULL in case of failure.
// It takes into account accessing the DOM across frames loaded from different domains.
CComQIPtr<IHTMLDocument2> HtmlWindowToHtmlDocument(CComQIPtr<IHTMLWindow2> spWindow)
{
     ATLASSERT(spWindow != NULL);

CComQIPtr<IHTMLDocument2> spDocument;
     HRESULT hRes = spWindow->get_document(&spDocument);
    
     if ((S_OK == hRes) && (spDocument != NULL))
     {
          // The html document was properly retrieved.
          return spDocument;
     }

// hRes could be E_ACCESSDENIED that means a security restriction that
     // prevents scripting across frames that loads documents from different internet domains.
     CComQIPtr<IWebBrowser2>  spBrws = HtmlWindowToHtmlWebBrowser(spWindow);
     if (spBrws == NULL)
     {
          return CComQIPtr<IHTMLDocument2>();
     }

// Get the document object from the IWebBrowser2 object.
     CComQIPtr<IDispatch> spDisp;
     hRes = spBrws->get_Document(&spDisp);
     spDocument = spDisp;

return spDocument;
}

// Converts a IHTMLWindow2 object to a IWebBrowser2. Returns NULL in case of failure.
CComQIPtr<IWebBrowser2> HtmlWindowToHtmlWebBrowser(CComQIPtr<IHTMLWindow2> spWindow)
{
     ATLASSERT(spWindow != NULL);

CComQIPtr<IServiceProvider>  spServiceProvider = spWindow;
     if (spServiceProvider == NULL)
     {
          return CComQIPtr<IWebBrowser2>();
     }

CComQIPtr<IWebBrowser2> spWebBrws;
     HRESULT hRes = spServiceProvider->QueryService(IID_IWebBrowserApp, IID_IWebBrowser2, (void**)&spWebBrws);
     if (hRes != S_OK)
     {
          return CComQIPtr<IWebBrowser2>();
     }

return spWebBrws;
}

附: 
IE(控件/接口)中主要有4个部分, Browser, Document, Frame/IFrame, Element , 其对应接口分别是 
Browser         -    IWebBrowser2
Document      -    IHTMLDocument2
Frame/IFrame-    IHTMLWindow2
Element         -    IHTMLElement
可以通过下面方法互相获取 
browser      -> document        IWebBrowser2::get_Document
document     -> frame           IHTMLDocument2::get_parentWindow
frame        -> document        IHTMLWindow2::get_document
frame        -> parent frame    IHTMLWindow2::get_parent
frame        -> children frames IHTMLWindow2::get_frames
element     -> Frame             IHTMLElement->QI(IHTMLFrameBase2) -> IHTMLFrameBase2->get_contentWindow -> IHTMLWindow2

ref: 
在多Frame的网页中怎么取出各个Frame的IHTMLDocument2的接口!急用.(高分)
在文章 When IHTMLWindow2::get_document returns E_ACCESSDENIED 解决了iframe 跨域访问的问题

posted on 2008-07-30 19:17 泡泡牛 阅读(5153) 评论(3)  编辑 收藏 引用 所属分类: Develop

获取IE (控件)的所有链接(包括Frameset, iframe)的更多相关文章

  1. WPF获取原始控件样式。

    要获取WPF控件的原始样式,需要我们安装Blend for Visual Studio. 然后,我们打开Blend for Visual Studio,创建一个WPF项目. 然后,我们向页面拖动一个B ...

  2. Selenium IDE安装和检查获取的控件路径技巧

    来源:http://www.jianshu.com/p/0ea2dc83549f 从学习Selenium 开始,都是自己写脚本,后来得知有个插件Selenium IDE可以录制脚本,也懒得用了,觉得自 ...

  3. UGUI 之获取当前控件的高度

    当Canvas Scaler选择Constant Pixel Size 当前的分辨率会被被固定,可以用RectTransform类里面的.rect变量值获取 height或Width. 在次情况下获取 ...

  4. winfrom获取用户控件里的控件对象

    如何获取用户控件里的控件对象呢,其实思路也是很简单的, 比如有一个panel 用户控件 里面有许多的其他控件. 那么要找出一个Label控件怎么找呢,好的.现在我们就开始 首先,一个foreach循环 ...

  5. 获取android控件的高度

    问题 如何获取一个控件的长和高,相信很多朋友第一眼看见这个问题都会觉得很简单,直接在onCreate里面调用getWidth.getMeasuredWidth不就可以获得了吗,但是,事实上是并没有简单 ...

  6. .net获取select控件中的文本内容

    .net获取select控件中的文本内容 2009-11-28 21:19小V古 | 分类:C#/.NET | 浏览1374次 <select id="SecType" st ...

  7. JS获取用户控件中的子控件Id

    用户控件 <asp:HiddenField ID="hfGradeId" runat="server" /> <asp:HiddenField ...

  8. 获取Repeater控件中的每一项数据

    var items = rptList.Items;//获取Repeater控件的所有项 foreach (RepeaterItem item in items)//遍历每一项内容 {   var t ...

  9. JS 获取Button控件的提交类型

    <script type="text/javascript"> <!--获取button控件的类型---> function isAuditOrCancel ...

随机推荐

  1. java.util下有一个Comparator(比较器)

    java.util下有一个Comparator(比较器) 它拥有compare(),用来比较两个方法. 要生成比较器,则用Sort中Sort(List,List(Compate)) 第二种方法更灵活, ...

  2. php -- PDO事务处理

    事务处理流程 开启事务 PDO::beginTransaction 事务操作 所有的实务操作就是增删改 事务提交 PDO::commit:成功后提交数据 PDO::rollback:失败后回滚数据 & ...

  3. 开启mysql日志及若干问题

    今天学习了mysql日志功能,以前也有所了解,只不过没有深入的学习,所以趁着“余热”,把我从网上找到的资料与实践 结合起来,总结一下其基本用法.学习从来都不是无趣的,就看你怎么看待学习. 1.查看查询 ...

  4. HTML 标签 参考手册

    按功能类别排列 基础 标签 描述 <!DOCTYPE>  定义文档类型. <html> 定义 HTML 文档. <title> 定义文档的标题. <body& ...

  5. Window发声函数Beep、MessageBeep

     C++ Code  1234567891011   WINBASEAPI BOOL WINAPI Beep(__in DWORD dwFreq,      __in DWORD dwDuration ...

  6. Ehcache缓存框架具体解释

    一.前言 ehcache是一个比較成熟的java缓存框架.它提供了用内存,磁盘文件存储.以及分布式存储方式等多种灵活的cache管理方案.ehcache最早从hibernate发展而来. 因为3.x的 ...

  7. PostgreSQL的.NET驱动程序Npgsql中参数对象的一个Bug

    最近将公司的项目从SqlServer移植到PostgreSQL数据库上来,在调用数据库的存储过程(自定义函数)的时候,发现一个奇怪的问题,老是报函数无法找到. 先看一个PgSQL存储过程: CREAT ...

  8. 第十六篇:Linux系统编程中环境变量的使用

    前言 在 UNIX Like 系统中,存有各类系统/应用程序的环境变量,可通过修改之改变系统/应用程序的执行效果:除此之外,用户还可以定义自己的环境变量,供自己写的程序使用. 本文将说明如何在程序中设 ...

  9. 《C++ Primer Plus》学习笔记——C++程序创建到运行的整个过程

    当你编写了一个C++,如何让它运行起来呢?具体的步骤取决于计算机环境和使用的C++编译器,但大体如下: 1.使用文本编辑器编写程序,并将其保存到文件中,这个文件就是程序的源代码. 2.编译源代码.这意 ...

  10. Windows游戏编程大师技巧之三角形填充

    一.三角形的种类 三角形一般可以分为如下的四种类型(这四种类型是对于计算机来说的,不是数学意义上的分类): 平顶三角形:就是在计算机中显示的上面两个顶点的Y坐标相同. 平底三角形:就是在计算机中显示的 ...