Страницы

Поиск по вопросам

воскресенье, 26 января 2020 г.

Как получить DOM через СОМ объект

#cpp #internet_explorer #dom #com


Я хочу программно нажимать на кнопки сайта. Для этого решил использовать СОМ объект
InternetExplorer. Выгрузить его в DOM  и там уже кликать по кнопкам. Делаю это так:

#include "stdafx.h"
#include "windows.h"
#import "progid:InternetExplorer.Application"

int _tmain(int argc, _TCHAR* argv[])
{

CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
bool showIE = true;
SHDocVw::IWebBrowserAppPtr  ptrIE(_T("InternetExplorer.Application"));

ptrIE->Visible = (showIE ? VARIANT_TRUE : VARIANT_FALSE);

ptrIE->Navigate("https://vk.com");
int i = 0;
// ждем пока загрузится страница по url
while (ptrIE->Busy)
    i++;

// получаем html-страницу как DOM (объектная модель документа)
//auto pdisp = ptrIE->Document;
IDispatch pdisp = (ptrIE->Document).GetInterfacePtr();
HRESULT hresult;
DISPID dispid;
OLECHAR *szMember = L"querySelector";
hresult = pdisp->GetIDsOfNames(IID_NULL, &szMember, 1, LOCALE_SYSTEM_DEFAULT, &dispid);

return 0;
}


Но при выполнении функции GetIDsOfNames программа вылетает с ошибкой access violation
reading location. Правильно ли я понимаю, что у меня в pdisp указатель в никуда?

UPDATE

Не надо было вызвывать GetInterfacePtr(), так как он возвращает указатель в никуда.
немного переделал код теперь он выглядит вот так:

#include "stdafx.h"
#include "windows.h"
#include "Mshtml.h"
#include "comutil.h"
#import "progid:InternetExplorer.Application"

int _tmain(int argc, _TCHAR* argv[])
{

CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
bool showIE = true;
SHDocVw::IWebBrowser2Ptr ptrIE(_T("InternetExplorer.Application"));

ptrIE->Visible = (showIE ? VARIANT_TRUE : VARIANT_FALSE);

HRESULT hr = ptrIE->Navigate("myUrl");
if (!SUCCEEDED(hr))
{
}
int i = 0;
// ждем пока загрузится страница по url
while (ptrIE->Busy)
    i++;

// получаем html-страницу как DOM (объектная модель документа)
IHTMLDocument3 *doc3;
hr = ptrIE->Document->QueryInterface(IID_IHTMLDocument3, (void**)&doc3);
if FAILED(hr) return(hr);

IHTMLElement *parentElem;
hr = doc3->getElementById(_com_util::ConvertStringToBSTR("intro-step-4"), &parentElem);
if FAILED(hr) return(hr);

IDispatch * pDisp;
hr = parentElem->get_children(&pDisp);
parentElem->Release();
if FAILED(hr) return(hr);

IHTMLElementCollection *elemCol;
hr = pDisp->QueryInterface(IID_IHTMLElementCollection, (void **)&elemCol);  
pDisp->Release();
if FAILED(hr) return(hr);

_variant_t index = 0;
hr = elemCol->item(index, index, &pDisp);
if FAILED(hr) return(hr);

IHTMLElement * childElem;
hr = pDisp->QueryInterface(IID_IHTMLElement, (void **)&childElem);
if FAILED(hr) return(hr);

BSTR *pszText = new BSTR;
hr = childElem->click();
if FAILED(hr) return(hr);
hr = childElem->get_innerText(pszText);
if FAILED(hr) return(hr);

    return 0;
}


Судя по тексту который я получаю в hr = childElem->get_innerText(pszText) я нашел
нужный мне элемент. Но метод click() хотя и возвращает S_OK, но клик не производит.
По крайней мере никакой реакции в открытом браузере нет. Что делать?
    


Ответы

Ответ 1



Используйте умные COM-указатели _COM_SMARTPTR_TYPEDEF(IHTMLDocument2, __uuidof(IHTMLDocument2)); _COM_SMARTPTR_TYPEDEF(IHTMLDocument3, __uuidof(IHTMLDocument3)); IDispatchPtr d = ptrIE->Document; IHTMLDocument2Ptr doc2; IHTMLDocument3Ptr doc3; d->QueryInterface(IID_IHTMLDocument2, (void**)&doc2); doc2->... d->QueryInterface(IID_IHTMLDocument3, (void**)&doc3); Я попробовал получить указатель на интерфейс IHtmlSelector (чтобы использовать метод querySelector, но у меня не вышло). У себя я делаю так: if ( SUCCEEDED(doc3->getElementsByTagName(L"HTML", &collection)) ){ long count = 0; if (SUCCEEDED(collection->get_length(&count)) && count ) { IDispatch* disp = 0; VARIANT v; ::VariantInit(&v); v.vt = VT_I4; v.iVal = 0; IElementSelectorPtr selector; collection->item(v, v, &disp); disp->QueryInterface(IID_IElementSelector, (void**)&selector); selector->querySelector(...); } } Но здесь это не работает. Правда IWebBrowserApp считается устаревшим. Используйте IWebBrowser2.

Комментариев нет:

Отправить комментарий