웹, HTML

IHTMLWindow2::get_document returns E_ACCESSDENIED 뱉을 경우

디버그정 2009. 9. 28. 11:39

   

     IHTMLWindow2 *pWin~~~~
    // 유효한 인터페이스가 존재하는 경우, 도큐먼트를 구할 시 다음과 같이 두 경우 고려 처리하면 된다.

     if(S_OK == (hr=pWin->get_document(&pDocFrame))){
       // 제대로 구해지면 여기서 프레임 도큐먼트를 가지고 작업
       //~~~~~~~~
       pDocFrame->Release();
      
     } else if(hr == E_ACCESSDENIED){ // 옆의 에러 발생시 아래와 같은 처리
       IServiceProvider *pSP=NULL;
       IWebBrowser2 *pWBSub=NULL;
       if(S_OK == pWin->QueryInterface(IID_IServiceProvider, (void**)&pSP)){
        if(S_OK == pSP->QueryService(IID_IWebBrowserApp, IID_IWebBrowser2, (void**)&pWBSub)){
         if(S_OK == pWBSub->get_Document(&pDisp)){
          if(S_OK == pDisp->QueryInterface(IID_IHTMLDocument2,(void**)&pDocFrame)){
           // 여기서 프레임 도큐먼트를 가지고 작업
           //~~~~~~~~~~~~~
           pDocFrame->Release();
          }
          pDisp->Release();
         }
         pWBSub->Release();
        }
        pSP->Release();
       }
      }
      pWin->Release();


================================ 관련 포스트 ====================================

When IHTMLWindow2::get_document returns E_ACCESSDENIED 뱉을 경우
 
When IHTMLWindow2::get_document returns E_ACCESSDENIED
Internet Explorer extensions usually needs to access HTML elements. When extensions are initialized they get a IWebBrowser2 pointer representing the browser. Starting with this pointer one can get any HTML element in the web page but to do that we need to browse a hierarchy of frames first. The simplest web pages only have one frame and one document. Web pages containing <frame> or <iframe> have a hierarchy of frames, each frame having its own document.

Here are the objects involved and the corresponding interfaces:

browser - IWebBrowser2
frame/iframe - IHTMLWindow2
document - IHTMLDocument2
element - IHTMLElement

The list bellow shows what method to call to get one object from another:

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

A normal call chain to get a HTML element is:

browser -> document -> frame -> child frame -> ... -> child frame -> document -> element
This will work almost all the time. The problems arise when different frames contain documents loaded from different internet domains. In this case IHTMLWindow2::get_document returns E_ACCESSDENIED when trying to get the document from the frame object. I think this happens to prevent cross frame scripting atacks.

Here is HtmlWindowToHtmlDocument function I wrote to be used instead IHTMLWindow2::get_document to bypass the restriction:

 

// 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;
}