2010. 11. 3. 13:52
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 |