CHtmlView의 C++에서 생성한 JScript를 모든 Frame에 대해 Inject하여 실행하기

2010/11/03 - [프로그래밍/Let's Share it] - CHtmlView의 C++에서 생성한 JScript를 Inject하여 실행하기
에서 version up된 내용을 다시 공유합니다.

이전 포스트에서 CHtmlView로 html에 jscript를 inject하는 방법을 알아보았는데, 문제는 frameset이 지원되지 않는다는 점입니다. 즉, a.html(=1.html + 2.html)로 되는 경우, 1.html/2.html에서는 jscript가 inject되지 않습니다. 따라서, frame을 enum하여 모든 frame에서 가능토록 하고, recursive 사용으로 인한 depth cut-off까지 구현된것을 공유합니다.

사용법은 간단한데, CHtmlView의 DocumentComplete와 NavigateComplete2 시기에,
InjectJScriptAllFrame(this, TEXT("function XXXX() {....}"), 10);
과 같이 사용하면 됩니다.

즉, MAX Frame Depth를 10으로 준 경우이며,
만약 10개가 넘는 경우, Navigate가 중단되며, 꼭 계층적으로 10개의 Frame까지 표시되는 것은 아니니,
주의하시기 바랍니다.

view plain하면 좀더 코드를 좀더 잘 확인할 수 있습니다.
  1. HRESULT InjectJScriptAllFrame(IN CHtmlView* pcWnd, IN LPCTSTR lpszJScript, IN INT nMaxRecurseFrame)  
  2. {  
  3.     HRESULT         hr              = S_OK;  
  4.     BOOL            bStackOverflow  = FALSE;  
  5.     IHTMLDocument2* pIHtmlDocument2 = NULL;  
  6.   
  7.     if ((NULL == pcWnd) || (NULL == lpszJScript))  
  8.     {  
  9.         hr = HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);  
  10.         ASSERT(FALSE);  
  11.         goto FINAL;  
  12.     }  
  13.   
  14.     if (NULL == pcWnd->GetHtmlDocument())  
  15.     {  
  16.         hr = HRESULT_FROM_WIN32(ERROR_NOT_READY);  
  17.         ASSERT(FALSE);  
  18.         goto FINAL;  
  19.     }  
  20.   
  21.     hr = pcWnd->GetHtmlDocument()->QueryInterface(IID_IHTMLDocument2, (VOID**)&pIHtmlDocument2);  
  22.     if (SUCCEEDED(hr))  
  23.     {  
  24.         if (NULL == pIHtmlDocument2)  
  25.         {  
  26.             hr = HRESULT_FROM_WIN32(ERROR_INTERNAL_ERROR);  
  27.             ASSERT(FALSE);  
  28.             goto FINAL;  
  29.         }  
  30.   
  31.         // HtmlDocument를 Frame 별로 recursive하게 JScript를 inject한다.  
  32.         // 만약, Frame이 MAX가 되었다면, hr은 HRESULT_FROM_WIN32(ERROR_STACK_OVERFLOW)가 리턴된다.  
  33.         hr = InjectJScriptByDocumentRecurse(pIHtmlDocument2, lpszJScript, nMaxRecurseFrame, 0, &bStackOverflow);  
  34.   
  35.         if (HRESULT_FROM_WIN32(ERROR_STACK_OVERFLOW) == hr)  
  36.         {  
  37.             // Stack overflow인 경우에는 stop~!  
  38.             pcWnd->Stop();  
  39.         }  
  40.     }  
  41.   
  42. FINAL:  
  43.   
  44.     if (NULL != pIHtmlDocument2)  
  45.     {  
  46.         pIHtmlDocument2->Release();  
  47.         pIHtmlDocument2 = NULL;  
  48.     }  
  49.   
  50.     return hr;  
  51. }  
  52.   
  53. HRESULT InjectJScriptByDocumentRecurse(IN IHTMLDocument2* pIHtmlDocument2, IN LPCTSTR lpszJScript, IN INT nMaxRecurseFrame, IN INT nCurDepth, OUT LPBOOL pbStackOverflow)  
  54. {  
  55.     HRESULT                     hr                      = S_OK;  
  56.     HRESULT                     hr2                     = S_OK;  
  57.     LONG                        nFrameCount             = 0;  
  58.     LONG                        i                       = 0;  
  59.     VARIANT                     varIndex                = {0,};  
  60.     VARIANT                     varDispWin              = {0,};  
  61.     BSTR                        bstrScript              = {0,};  
  62.     BSTR                        bstrElementType         = {0,};  
  63.     BSTR                        bstrInsertWhere         = {0,};  
  64.     IHTMLElement*               pIHtmlElement           = NULL;  
  65.     IHTMLElement2*              pIHtmlElement2          = NULL;  
  66.     IHTMLElement*               pIHtmlElementScript     = NULL;  
  67.     IHTMLScriptElement*         pIHtmlScript            = NULL;  
  68.     IHTMLFramesCollection2*     pIHtmlFramesCollection  = NULL;  
  69.     IHTMLWindow2*               pIHtmlWindow            = NULL;  
  70.     IHTMLDocument2*             pIHtmlDocument2Frame    = NULL;  
  71.   
  72.     if ((NULL == pIHtmlDocument2) || (NULL == lpszJScript) || (NULL == pbStackOverflow))  
  73.     {  
  74.         hr = HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);  
  75.         goto FINAL;  
  76.     }  
  77.   
  78.     if (nCurDepth >= nMaxRecurseFrame)  
  79.     {  
  80.         hr = HRESULT_FROM_WIN32(ERROR_STACK_OVERFLOW);  
  81.         *pbStackOverflow = TRUE;  
  82.         goto FINAL;  
  83.     }  
  84.   
  85.     if (TRUE == *pbStackOverflow)  
  86.     {  
  87.         hr = HRESULT_FROM_WIN32(ERROR_STACK_OVERFLOW);  
  88.         goto FINAL;  
  89.     }  
  90.   
  91.     // insertAdjacentElement에 들어갈 Param을 결정한다.  
  92.     bstrScript      = ::SysAllocString(T2COLE(lpszJScript));  
  93.     bstrElementType = ::SysAllocString(T2COLE(TEXT("script")));  
  94.     bstrInsertWhere = ::SysAllocString(T2COLE(TEXT("afterBegin")));  
  95.   
  96.     hr = pIHtmlDocument2->get_body(&pIHtmlElement);  
  97.     if ((FAILED(hr)) || (NULL == pIHtmlElement))  
  98.     {  
  99.         if ((SUCCEEDED(hr)) && (NULL == pIHtmlElement))  
  100.         {  
  101.             hr = HRESULT_FROM_WIN32(ERROR_NOT_READY);  
  102.             goto FINAL;  
  103.         }  
  104.   
  105.         pIHtmlElement = NULL;  
  106.         ASSERT(FALSE);  
  107.         goto FINAL;  
  108.     }  
  109.   
  110.     hr = pIHtmlElement->QueryInterface(IID_IHTMLElement2, (VOID**)&pIHtmlElement2);  
  111.     if (FAILED(hr))  
  112.     {  
  113.         pIHtmlElement2 = NULL;  
  114.         ASSERT(FALSE);  
  115.         goto FINAL;  
  116.     }  
  117.   
  118.     hr = pIHtmlDocument2->createElement(bstrElementType, &pIHtmlElementScript);  
  119.     if (FAILED(hr))  
  120.     {  
  121.         pIHtmlElementScript = NULL;  
  122.         ASSERT(FALSE);  
  123.         goto FINAL;  
  124.     }  
  125.   
  126.     hr = pIHtmlElementScript->QueryInterface(IID_IHTMLScriptElement, (VOID**)&pIHtmlScript);  
  127.     if (FAILED(hr))  
  128.     {  
  129.         pIHtmlScript = NULL;  
  130.         ASSERT(FALSE);  
  131.         goto FINAL;  
  132.     }  
  133.   
  134.     hr = pIHtmlScript->put_defer(VARIANT_TRUE);  
  135.     if (FAILED(hr))  
  136.     {  
  137.         ASSERT(FALSE);  
  138.         goto FINAL;  
  139.     }  
  140.   
  141.     hr = pIHtmlScript->put_text(bstrScript);  
  142.     if (FAILED(hr))  
  143.     {  
  144.         ASSERT(FALSE);  
  145.         goto FINAL;  
  146.     }  
  147.   
  148.     hr = pIHtmlElement2->insertAdjacentElement(bstrInsertWhere, pIHtmlElementScript, NULL);  
  149.     if (FAILED(hr))  
  150.     {  
  151.         ASSERT(FALSE);  
  152.         goto FINAL;  
  153.     }  
  154.   
  155.     // 여기까지 왔다면, 일단 성공~  
  156.     hr = S_OK;  
  157.   
  158.     hr2 = pIHtmlDocument2->get_frames(&pIHtmlFramesCollection);  
  159.     if (FAILED(hr2))  
  160.     {  
  161.         // Frame이 없는 깔끔한 경우이다~  
  162.         goto FINAL;  
  163.     }  
  164.   
  165.     hr2 = pIHtmlFramesCollection->get_length(&nFrameCount);  
  166.     if (FAILED(hr2))  
  167.     {  
  168.         goto FINAL;  
  169.     }  
  170.   
  171.     for (i=0; i<nframecount; vardispwin.pdispval-="" {="" !="varDispWin.pdispVal)" (null="" if="" vardispwin.pdispval="NULL;" vardispwin.vt="VT_DISPATCH;" varindex.lval="i;" varindex.vt="VT_I4;" i++)="">Release();  
  172.             varDispWin.pdispVal = NULL;  
  173.         }  
  174.   
  175.         hr2 = pIHtmlFramesCollection->item(&varIndex, &varDispWin);  
  176.         if (FAILED(hr2))  
  177.         {  
  178.             continue;  
  179.         }  
  180.   
  181.         if (NULL == varDispWin.pdispVal)  
  182.         {  
  183.             ASSERT(FALSE);  
  184.             continue;  
  185.         }  
  186.   
  187.         if (NULL != pIHtmlWindow)  
  188.         {  
  189.             pIHtmlWindow->Release();  
  190.             pIHtmlWindow = NULL;  
  191.         }  
  192.   
  193.         hr2 = varDispWin.pdispVal->QueryInterface(IID_IHTMLWindow2, (VOID**)&pIHtmlWindow);  
  194.         if (FAILED(hr2))  
  195.         {  
  196.             continue;  
  197.         }  
  198.   
  199.         if (NULL == pIHtmlWindow)  
  200.         {  
  201.             ASSERT(FALSE);  
  202.             continue;  
  203.         }  
  204.   
  205.         if (NULL != pIHtmlDocument2Frame)  
  206.         {  
  207.             pIHtmlDocument2Frame->Release();  
  208.             pIHtmlDocument2Frame = NULL;  
  209.         }  
  210.   
  211.         hr2 = pIHtmlWindow->get_document(&pIHtmlDocument2Frame);  
  212.         if (FAILED(hr2))  
  213.         {  
  214.             continue;  
  215.         }  
  216.   
  217.         if (NULL == pIHtmlDocument2Frame)  
  218.         {  
  219.             ASSERT(FALSE);  
  220.             continue;  
  221.         }  
  222.   
  223.         // Recursive 실행~!!!  
  224.         hr2 = InjectJScriptByDocumentRecurse(pIHtmlDocument2Frame, lpszJScript, nMaxRecurseFrame, nCurDepth+1, pbStackOverflow);  
  225.   
  226.         // StackOverflow  
  227.         if (HRESULT_FROM_WIN32(ERROR_STACK_OVERFLOW) == hr2)  
  228.         {  
  229.             (*pbStackOverflow) = TRUE;  
  230.             hr = HRESULT_FROM_WIN32(ERROR_STACK_OVERFLOW);  
  231.             break;  
  232.         }  
  233.     }  
  234.   
  235. FINAL:  
  236.   
  237.     if (NULL != pIHtmlDocument2Frame)  
  238.     {  
  239.         pIHtmlDocument2Frame->Release();  
  240.         pIHtmlDocument2Frame = NULL;  
  241.     }  
  242.   
  243.     if (NULL != pIHtmlWindow)  
  244.     {  
  245.         pIHtmlWindow->Release();  
  246.         pIHtmlWindow = NULL;  
  247.     }  
  248.   
  249.     if (NULL != varDispWin.pdispVal)  
  250.     {  
  251.         varDispWin.pdispVal->Release();  
  252.         varDispWin.pdispVal = NULL;  
  253.     }  
  254.   
  255.     if (NULL != pIHtmlScript)  
  256.     {  
  257.         pIHtmlScript->Release();  
  258.         pIHtmlScript = NULL;  
  259.     }  
  260.   
  261.     if (NULL != pIHtmlElementScript)  
  262.     {  
  263.         pIHtmlElementScript->Release();  
  264.         pIHtmlElementScript = NULL;  
  265.     }  
  266.   
  267.     if (NULL != pIHtmlElement2)  
  268.     {  
  269.         pIHtmlElement2->Release();  
  270.         pIHtmlElement2 = NULL;  
  271.     }  
  272.   
  273.     if (NULL != pIHtmlElement)  
  274.     {  
  275.         pIHtmlElement->Release();  
  276.         pIHtmlElement = NULL;  
  277.     }  
  278.   
  279.     ::SysFreeString(bstrScript);  
  280.     ::SysFreeString(bstrElementType);  
  281.     ::SysFreeString(bstrInsertWhere);  
  282.   
  283.     return hr;  
  284. }  
  285. </nframecount;>