CHtmlView의 C++에서 생성한 JScript를 Inject하여 실행하기
2010. 11. 3. 13:52 in 프로그래밍/Let's Share it

CHtmlView(CDHtmlDialog, CHtmlDialog)등에서 HTML을 로드하여 실행하게 됩니다.
혹시 이런 생각을 해보신적 있는지요?
기존 HTML 소스에 동적으로 JScript를 추가하고, 그 함수를 호출받고 싶다...즉, C++에서 DocumentComplete Timing때, C++에서 정의한 JScript 함수를 넣는다. Body OnLoad()에 그 함수를 대체해서 넣는다. 즉, 기존 Html이
단, 추가할 JScript 소스는 C++에서 명시적으로 정의한다.
==>
즉, 동일한 URL에 대해 기존의 일반 웹 브라우저와 조금 다른 웹(즉, 뭐.. 화면 상단에 강제적인 버튼 추과와 그 처리등등...)을 표현하고 싶다.
function OnLoad()
{
alert('hello');
}
{
alert('hello');
}
였다면,
function OnLoad()
{
alert('hello'); // <- 기존 내용
inject();
}
function inject()
{
alert('injected');
}
{
alert('hello'); // <- 기존 내용
inject();
}
function inject()
{
alert('injected');
}
와 같이 수정하면, inject()가 실행될 것입니다.
즉, C++의 DocumentComplete에서,
InjectScript(..., "function OnLoad(){alert('hello');inject();}function inject(){alert('injected');}", ...)
를 호출하는 것입니다.
이를 위한 소스 코드를 아래와 같이 공유합니다.
사용은 CHtmlView의 OnDocumentComplete나 DocumentComplete 때 아래 함수를 호출하면 됩니다.
(view plain을 누르시면 코드 확인이 쉽습니다.)
즉, C++의 DocumentComplete에서,
InjectScript(..., "function OnLoad(){alert('hello');inject();}function inject(){alert('injected');}", ...)
를 호출하는 것입니다.
이를 위한 소스 코드를 아래와 같이 공유합니다.
사용은 CHtmlView의 OnDocumentComplete나 DocumentComplete 때 아래 함수를 호출하면 됩니다.
(view plain을 누르시면 코드 확인이 쉽습니다.)
- HRESULT InjectJScript(IN CHtmlView* pcWnd, IN LPCTSTR lpszJScript)
- {
- if ((NULL == pcWnd) || (NULL == lpszJScript))
- {
- return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
- }
- return InjectJScript(pcWnd->GetHtmlDocument(), lpszJScript);
- }
- // HTML에 JScript를 이식시킨다.
- HRESULT InjectJScript(IN LPDISPATCH pDispatch, IN LPCTSTR lpszJScript)
- {
- HRESULT hr = S_OK;
- IHTMLDocument2* pIHtmlDocument2 = NULL;
- BSTR bstrScript = {0,};
- BSTR bstrElementType = {0,};
- BSTR bstrInsertWhere = {0,};
- IHTMLElement* pIHtmlElement = NULL;
- IHTMLElement2* pIHtmlElement2 = NULL;
- IHTMLElement* pIHtmlElementScript = NULL;
- IHTMLScriptElement* pIHtmlScript = NULL;
- if ((NULL == pDispatch) || (NULL == lpszJScript))
- {
- hr = HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
- goto FINAL;
- }
- bstrScript = ::SysAllocString(T2COLE(lpszJScript));
- bstrElementType = ::SysAllocString(T2COLE(TEXT("script")));
- bstrInsertWhere = ::SysAllocString(T2COLE(TEXT("afterBegin")));
- hr = pDispatch->QueryInterface(IID_IHTMLDocument2, (VOID**)&pIHtmlDocument2);
- if (FAILED(hr))
- {
- pIHtmlDocument2 = NULL;
- ASSERT(FALSE);
- goto FINAL;
- }
- hr = pIHtmlDocument2->get_body(&pIHtmlElement);
- if (FAILED(hr))
- {
- 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;
- FINAL:
- 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;
- }
- if (NULL != pIHtmlDocument2)
- {
- pIHtmlDocument2->Release();
- pIHtmlDocument2 = NULL;
- }
- ::SysFreeString(bstrScript);
- ::SysFreeString(bstrElementType);
- ::SysFreeString(bstrInsertWhere);
- return hr;
- }
ps)
위 코드의 중심은 insertAdjacentElement인데, 좀더 연구를 하면, 기존의 함수를 그대로 두고, OnLoad시 기존의 함수는 그대로 실행되고, 그때 연속하여 Inject 함수를 실행할 수 있게금 할 수 도 있어 보입니다. 이건 노력 여부에 달린 문제네요... 물론, 단순하게 JScript 대신 Tag Element로 insertAdjacentElement하여 해결될 수 있습니다.
하지만, 일반 Tag Element를 insertAdjacentElement하는 예는 많은데, 순수하게 JScript만 되는 경우는 없어서 한번 만들어본 내용입니다.
'프로그래밍 > Let's Share it' 카테고리의 다른 글
어떤 계정에서도 읽고 쓸수 있는 경로 구하기 (0) | 2010.12.10 |
---|---|
CHtmlView의 C++에서 생성한 JScript를 모든 Frame에 대해 Inject하여 실행하기 (1) | 2010.12.08 |
CBitmapButton의 투명(Transparent)와 Hover 지원하기 (22) | 2010.11.01 |
Crash 발생시 스스로 미니 덤프를 생성하는 코드 공유와 간략한 덤프 분석 방법 (1) | 2009.09.25 |
IOCP를 이용한 Thread Safe Job Queue (3) | 2009.09.24 |