Появилась необходимость использования функций JavaScript для обработких HMTL, пошарился по гуглу нашел несколько примеров и в итоге на данный момент имею следующие 2 метода: 1-й метод: выполнение кода, передаваемого в ScriptCode, используя IHTMLDocument2->execScript Код (Text): HRESULT PExecScript (IHTMLDocument2 *pNewDoc, CHAR *ScriptCode, CHAR *ScriptLang) { if (!pNewDoc || !ScriptCode || !ScriptLang) return E_FAIL; HRESULT hr = E_FAIL; IHTMLWindow2 *pWindow2 = NULL; if (SUCCEEDED(pNewDoc->get_parentWindow(&pWindow2))) { VARIANT pvarRet = {0}; CComBSTR BstrLanguage(ScriptLang); CComBSTR BstrFunction(ScriptCode); hr = pWindow2->execScript(BstrFunction, BstrLanguage, &pvarRet); VariantClear(&pvarRet); pWindow2->Release(); } return hr; } 2-й метод: выполнение функции, находящейся в коде ХТМЛ, имя которой передается в FunctionName, используя IDispatch->Invoke Код (Text): HRESULT CallJScript (IHTMLDocument2 *pNewDoc, CHAR *FunctionName) { if (!pNewDoc || !FunctionName) return E_FAIL; IDispatch *spScript; HRESULT hr = pNewDoc->get_Script(&spScript); if(FAILED(hr)) return hr; BSTR bstrMember = A2WBSTR(FunctionName); DISPID dispid = NULL; hr = spScript->GetIDsOfNames(IID_NULL,&bstrMember,1,LOCALE_SYSTEM_DEFAULT,&dispid); SysFreeString(bstrMember); if(FAILED(hr)) return hr; DISPPARAMS dispparams = {0}; EXCEPINFO excepInfo = {0}; VARIANT vaResult; UINT nArgErr = (UINT)-1; hr = spScript->Invoke(dispid,IID_NULL,0,DISPATCH_METHOD,&dispparams,&vaResult,&excepInfo,&nArgErr); VariantClear(&vaResult); return hr; } Оба метода прекрастно работают если получать интерфейс IHTMLDocument2 через IWebBrowser2 от инстанции браузера. Мне же необходимо обойтись без ненужных вызовов браузера + нужно чтобы на странице исполнялся только мой скрипт. Для получения интерфейса IHTMLDocument2 для любой строки использую приведенную ниже функцию (которая в свою очередь вызывает одну из вышеуказанных, в зависимости от параметров). Однако получая IHTMLDocument2 таким образом возникают следующие проблемы: 1. функция HRESULT PExecScript() при выполнении базовых скриптов выдает странные результаты, к примеру если выполнить этот код: Код (Text): CHAR *Script = \ "var tr = document.body;" \ "if (tr) alert(tr.innerHTML); else alert('fail');"; BOOL bResult = ExecScript(File, Script, "javascript"); то отображается какойто левый контент, не относящийся к тегу <body>, и подобных примеров куча! Нормально выполняются только простейшие функции. 2. в HRESULT CallJScript() не получается интерфейс IDispatch *spScript, pNewDoc->get_Script(&spScript) выдает ошибку E_PENDING Кстати получая IHTMLDocument2 через ExecScript, ReadyState у полученного IHTMLDocument2 всегда равен unitialized! Видимо по этой причине возникает ошибка E_PENDING и вообще все проблемы. Исходя из этого, задаюсь следующими вопросами: - КАК изменить ReadyState у IHTMLDocument2 ? - КАК получить результат выполнения javascript-функции? Более подробно: 1. Как получить IHTMLDocument2 так, чтобы ReadyState == complete? Возможно ли вручную изменить ReadyState? 2. Если в качестве параметра функции PExecScript передавать document.write(), то скрипт функция вносит нужные изменения в код, однако нужные изменения невозможно получить от IHTML* интерфейсов! В принципе меня бы устроил этот подход, если бы можно было получить результат работы javascript-функции Код (Text): CHAR *Script = \ "document.write('<html><body><a id=32932 href=b>ok</a> body content</body></html');" \ "if (tr) alert(tr.innerHTML); else alert('fail');"; 3. Почемуто не работает IHTMLDocument2::write(), видимо опять-таки проблема кроется в ReadyState == unitialized Основная функция в контексте которой вызываются методы: Код (Text): BOOL ExecScript (CHAR *HTML, CHAR *ScriptCode, CHAR *ScriptLang, CHAR *FunctionName) { if (!HTML) { return FALSE; } HRESULT hr = E_FAIL; OLECHAR *oleHTML = (OLECHAR *) A2WBSTR(HTML); IHTMLDocument2 *pDoc = NULL; CoInitialize(NULL); if (SUCCEEDED(CoCreateInstance(CLSID_HTMLDocument, NULL, CLSCTX_INPROC_SERVER, IID_IHTMLDocument2, (LPVOID *) &pDoc)) && pDoc) { IPersistStreamInit *pPersist = NULL; if (SUCCEEDED(pDoc->QueryInterface(IID_IPersistStreamInit, (LPVOID *) &pPersist)) && pPersist) { IMarkupServices *pMS = NULL; pPersist->InitNew(); pPersist->Release(); if (SUCCEEDED(pDoc->QueryInterface(IID_IMarkupServices, (LPVOID *) &pMS)) && pMS) { IMarkupContainer *pMC = NULL; IMarkupPointer *pMkStart = NULL; IMarkupPointer *pMkFinish = NULL; pMS->CreateMarkupPointer(&pMkStart); pMS->CreateMarkupPointer(&pMkFinish); if (SUCCEEDED(pMS->ParseString(oleHTML, 0, &pMC, pMkStart, pMkFinish)) && pMC) { IHTMLDocument2 *pNewDoc = NULL; if (SUCCEEDED(pMC->QueryInterface(IID_IHTMLDocument, (LPVOID *) &pNewDoc)) && pNewDoc) { if (FunctionName) { hr = CallJScript(pNewDoc, FunctionName); } else if (ScriptCode && ScriptLang) { hr = PExecScript(pNewDoc, ScriptCode, ScriptLang); } pNewDoc->Release(); } pMC->Release(); } if (pMkStart) pMkStart->Release(); if (pMkFinish) pMkFinish->Release(); pMS->Release(); } } pDoc->Release(); } CoUninitialize(); SysFreeString((BSTR) oleHTML); return hr == S_OK; }
- КАК получить результат выполнения javascript-функции? - vaResult вот твой резалт, там правда могут быть VT_DISPATCH и т.п. хрень Использовал вызов по имени через dispatch. Для обратной связи можно также использовать external. Windowless HTMLDocument я пользовался, но там все сложнее чем у тебя в сниппете. В качестве базы использовался http://msdn.microsoft.com/en-us/library/bb508516(VS.85).aspx (reusing mshtml). По поводу работоспособности скриптов в windowless, не помню использовал ли их.
Уточню вопрос: - КАК получить результат выполнения javascript-функции, вызванной HRESULT PExecScript ()?
Осталась одна проблема: корректно загрузить хтмл в память! Т.к. приведенный мной пример при любых обсоятелствах при иницализации JS (execScript) сбрасывает хтмл до такого: Код (Text): <HEAD></HEAD> <BODY> <P> </P></BODY> возможно нужно перед загрузкой кода инициализировать js или чтото еще( прошу помочь кто чем может) этот вопрос решился!: - КАК получить результат выполнения javascript-функции, вызванной HRESULT PExecScript ()? вот таким вот образом (получаю обработанный хтмл код, в нем записан скрытый элемент div с результатами): Код (Text): IHTMLDocument2 *Doc2Intf = NULL; if (SUCCEEDED(pWindow2->get_document(&Doc2Intf))) { IHTMLDocument3 *Doc3Intf = NULL; if (SUCCEEDED(Doc2Intf->QueryInterface(IID_IHTMLDocument3, (VOID **) &Doc3Intf)) && Doc3Intf) { IHTMLElement *DocElem = NULL; if (SUCCEEDED(Doc3Intf->get_documentElement(&DocElem)) && DocElem) { BSTR InnerHTML; if (SUCCEEDED(DocElem->get_innerHTML(&InnerHTML))) { if (ExecutionResult) *ExecutionResult = WCharToAnsi((WCHAR *) InnerHTML); } DocElem->Release(); } Doc3Intf->Release(); } Doc2Intf->Release(); }
Твой способ получения резалта от функции слишком сложный. external выглядит проще. Загрузка делается так http://msdn.microsoft.com/en-us/library/aa752047%28VS.85%29.aspx( persist stream + CreateStreamOnHglobal)