날자별

2021 2월
1234567
891011121314
15161718192021
22232425262728

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

출처] http://greenfishblog.tistory.com/46

CHtmlView(CDHtmlDialog, CHtmlDialog)등에서 HTML을 로드하여 실행하게 됩니다.
혹시 이런 생각을 해보신적 있는지요?

기존 HTML 소스에 동적으로 JScript를 추가하고, 그 함수를 호출받고 싶다…
단, 추가할 JScript 소스는 C++에서 명시적으로 정의한다.

즉, 동일한 URL에 대해 기존의 일반 웹 브라우저와 조금 다른 웹(즉, 뭐.. 화면 상단에 강제적인 버튼 추과와 그 처리등등…)을 표현하고 싶다.
즉, C++에서 DocumentComplete Timing때, C++에서 정의한 JScript 함수를 넣는다. Body OnLoad()에 그 함수를 대체해서 넣는다. 즉, 기존 Html이
[javascript]function OnLoad()
{
alert(‘hello’);
}[/javascript]
였다면,
[javascript]function OnLoad()
{
alert(‘hello’); // <- 기존 내용
inject();
}
function inject()
{
alert(‘injected’);
}[/javascript]
와 같이 수정하면, inject()가 실행될 것입니다.
즉, C++의 DocumentComplete에서,
[javascript]InjectScript(…, “function OnLoad(){alert(‘hello’);inject();}function inject(){alert(‘injected’);}”, …)[/javascript]
를 호출하는 것입니다.
이를 위한 소스 코드를 아래와 같이 공유합니다.
사용은 CHtmlView의 OnDocumentComplete나 DocumentComplete 때 아래 함수를 호출하면 됩니다.
(view plain을 누르시면 코드 확인이 쉽습니다.)

[cpp]HRESULT InjectJScriptAllFrame(IN CHtmlView* pcWnd, IN LPCTSTR lpszJScript, IN INT nMaxRecurseFrame)
{
HRESULT hr = S_OK;
BOOL bStackOverflow = FALSE;
IHTMLDocument2* pIHtmlDocument2 = NULL;

if ((NULL == pcWnd) || (NULL == lpszJScript))
{
hr = HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
ASSERT(FALSE);
goto FINAL;
}

if (NULL == pcWnd->GetHtmlDocument())
{
hr = HRESULT_FROM_WIN32(ERROR_NOT_READY);
ASSERT(FALSE);
goto FINAL;
}

hr = pcWnd->GetHtmlDocument()->QueryInterface(IID_IHTMLDocument2, (VOID**)&pIHtmlDocument2);
if (SUCCEEDED(hr))
{
if (NULL == pIHtmlDocument2)
{
hr = HRESULT_FROM_WIN32(ERROR_INTERNAL_ERROR);
ASSERT(FALSE);
goto FINAL;
}

// HtmlDocument를 Frame 별로 recursive하게 JScript를 inject한다.
// 만약, Frame이 MAX가 되었다면, hr은 HRESULT_FROM_WIN32(ERROR_STACK_OVERFLOW)가 리턴된다.
hr = InjectJScriptByDocumentRecurse(pIHtmlDocument2, lpszJScript, nMaxRecurseFrame, 0, &bStackOverflow);

if (HRESULT_FROM_WIN32(ERROR_STACK_OVERFLOW) == hr)
{
// Stack overflow인 경우에는 stop~!
pcWnd->Stop();
}
}

FINAL:

if (NULL != pIHtmlDocument2)
{
pIHtmlDocument2->Release();
pIHtmlDocument2 = NULL;
}

return hr;
}

HRESULT InjectJScriptByDocumentRecurse(IN IHTMLDocument2* pIHtmlDocument2, IN LPCTSTR lpszJScript, IN INT nMaxRecurseFrame, IN INT nCurDepth, OUT LPBOOL pbStackOverflow)
{
HRESULT hr = S_OK;
HRESULT hr2 = S_OK;
LONG nFrameCount = 0;
LONG i = 0;
VARIANT varIndex = {0,};
VARIANT varDispWin = {0,};
BSTR bstrScript = {0,};
BSTR bstrElementType = {0,};
BSTR bstrInsertWhere = {0,};
IHTMLElement* pIHtmlElement = NULL;
IHTMLElement2* pIHtmlElement2 = NULL;
IHTMLElement* pIHtmlElementScript = NULL;
IHTMLScriptElement* pIHtmlScript = NULL;
IHTMLFramesCollection2* pIHtmlFramesCollection = NULL;
IHTMLWindow2* pIHtmlWindow = NULL;
IHTMLDocument2* pIHtmlDocument2Frame = NULL;

if ((NULL == pIHtmlDocument2) || (NULL == lpszJScript) || (NULL == pbStackOverflow))
{
hr = HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
goto FINAL;
}

if (nCurDepth >= nMaxRecurseFrame)
{
hr = HRESULT_FROM_WIN32(ERROR_STACK_OVERFLOW);
*pbStackOverflow = TRUE;
goto FINAL;
}

if (TRUE == *pbStackOverflow)
{
hr = HRESULT_FROM_WIN32(ERROR_STACK_OVERFLOW);
goto FINAL;
}

// insertAdjacentElement에 들어갈 Param을 결정한다.
bstrScript = ::SysAllocString(T2COLE(lpszJScript));
bstrElementType = ::SysAllocString(T2COLE(TEXT(“script”)));
bstrInsertWhere = ::SysAllocString(T2COLE(TEXT(“afterBegin”)));

hr = pIHtmlDocument2->get_body(&pIHtmlElement);
if ((FAILED(hr)) || (NULL == pIHtmlElement))
{
if ((SUCCEEDED(hr)) && (NULL == pIHtmlElement))
{
hr = HRESULT_FROM_WIN32(ERROR_NOT_READY);
goto FINAL;
}

pIHtmlElement = NULL;
ASSERT(FALSE);
goto FINAL;
}

hr = pIHtmlElement->QueryInterface(IID_IHTMLElement2, (VOID**)&pIHtmlElement2);
if (FAILED(hr))
{
pIHtmlElement2 = NULL;
ASSERT(FALSE);
goto FINAL;
}

hr = pIHtmlDocument2->createElement(bstrElementType, &pIHtmlElementScript);
if (FAILED(hr))
{
pIHtmlElementScript = NULL;
ASSERT(FALSE);
goto FINAL;
}

hr = pIHtmlElementScript->QueryInterface(IID_IHTMLScriptElement, (VOID**)&pIHtmlScript);
if (FAILED(hr))
{
pIHtmlScript = NULL;
ASSERT(FALSE);
goto FINAL;
}

hr = pIHtmlScript->put_defer(VARIANT_TRUE);
if (FAILED(hr))
{
ASSERT(FALSE);
goto FINAL;
}

hr = pIHtmlScript->put_text(bstrScript);
if (FAILED(hr))
{
ASSERT(FALSE);
goto FINAL;
}

hr = pIHtmlElement2->insertAdjacentElement(bstrInsertWhere, pIHtmlElementScript, NULL);
if (FAILED(hr))
{
ASSERT(FALSE);
goto FINAL;
}

// 여기까지 왔다면, 일단 성공~
hr = S_OK;

hr2 = pIHtmlDocument2->get_frames(&pIHtmlFramesCollection);
if (FAILED(hr2))
{
// Frame이 없는 깔끔한 경우이다~
goto FINAL;
}

hr2 = pIHtmlFramesCollection->get_length(&nFrameCount);
if (FAILED(hr2))
{
goto FINAL;
}

for (i=0; iRelease();
varDispWin.pdispVal = NULL;
}

hr2 = pIHtmlFramesCollection->item(&varIndex, &varDispWin);
if (FAILED(hr2))
{
continue;
}

if (NULL == varDispWin.pdispVal)
{
ASSERT(FALSE);
continue;
}

if (NULL != pIHtmlWindow)
{
pIHtmlWindow->Release();
pIHtmlWindow = NULL;
}

hr2 = varDispWin.pdispVal->QueryInterface(IID_IHTMLWindow2, (VOID**)&pIHtmlWindow);
if (FAILED(hr2))
{
continue;
}

if (NULL == pIHtmlWindow)
{
ASSERT(FALSE);
continue;
}

if (NULL != pIHtmlDocument2Frame)
{
pIHtmlDocument2Frame->Release();
pIHtmlDocument2Frame = NULL;
}

hr2 = pIHtmlWindow->get_document(&pIHtmlDocument2Frame);
if (FAILED(hr2))
{
continue;
}

if (NULL == pIHtmlDocument2Frame)
{
ASSERT(FALSE);
continue;
}

// Recursive 실행~!!!
hr2 = InjectJScriptByDocumentRecurse(pIHtmlDocument2Frame, lpszJScript, nMaxRecurseFrame, nCurDepth+1, pbStackOverflow);

// StackOverflow
if (HRESULT_FROM_WIN32(ERROR_STACK_OVERFLOW) == hr2)
{
(*pbStackOverflow) = TRUE;
hr = HRESULT_FROM_WIN32(ERROR_STACK_OVERFLOW);
break;
}
}

FINAL:

if (NULL != pIHtmlDocument2Frame)
{
pIHtmlDocument2Frame->Release();
pIHtmlDocument2Frame = NULL;
}

if (NULL != pIHtmlWindow)
{
pIHtmlWindow->Release();
pIHtmlWindow = NULL;
}

if (NULL != varDispWin.pdispVal)
{
varDispWin.pdispVal->Release();
varDispWin.pdispVal = NULL;
}

if (NULL != pIHtmlScript)
{
pIHtmlScript->Release();
pIHtmlScript = NULL;
}

if (NULL != pIHtmlElementScript)
{
pIHtmlElementScript->Release();
pIHtmlElementScript = NULL;
}

if (NULL != pIHtmlElement2)
{
pIHtmlElement2->Release();
pIHtmlElement2 = NULL;
}

if (NULL != pIHtmlElement)
{
pIHtmlElement->Release();
pIHtmlElement = NULL;
}

::SysFreeString(bstrScript);
::SysFreeString(bstrElementType);
::SysFreeString(bstrInsertWhere);

return hr;
}[/cpp]

Leave a Reply

이 사이트는 스팸을 줄이는 아키스밋을 사용합니다. 댓글이 어떻게 처리되는지 알아보십시오.