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 跨域访问的问题