2013-04-17 2 views
11

[Пересмотренный еще раз для ясности]Как автоматизировать IE webapp, который появляется модальный диалог HTML?

У меня есть программа C++, которая взаимодействует с веб-сайта. Сайт является специфичным для IE, и моя программа тоже.

Я подключаюсь к исполняемому экземпляру IE обычным способом (не работает - см. Код). После того, как я получаю IWebBrowser2, у меня нет проблем с получением в IHTMLDocument2 и взаимодействующий с отдельными IHTMLElement объектов, заполнение полей и нажав кнопки.

Но если на веб-странице есть javascript, который вызывает window.showModalDialog, я застрял: мне нужно взаимодействовать с элементами HTML во всплывающем окне, как и на других страницах; но я не могу получить его IWebBrowser2.

Всплывающее окно всегда называется «Диалог веб-страниц» и представляет собой окно типа Internet Explorer_TridentDlgFrame, содержащее Internet Explorer_Server. Но я не могу получить IWebBrowser2 из Internet Explorer_Server окна так, как я могу, когда это обычный экземпляр IE.

я могу получить IHTMLDocument2Ptr, но когда я пытаюсь получить IWebBrowser2 я получаю HRESULT из E_NOINTERFACE.

код довольно стандартный материал, и работает хорошо, если это «нормальный» окно IE

IHTMLDocument2Ptr pDoc; 
LRESULT lRes; 

/* hWndChild is an instance of class "Internet Explorer_Server" */ 

UINT nMsg = ::RegisterWindowMessage("WM_HTML_GETOBJECT"); 
::SendMessageTimeout(hWndChild, nMsg, 0L, 0L, SMTO_ABORTIFHUNG, 1000, 
    (DWORD*)&lRes); 

LPFNOBJECTFROMLRESULT pfObjectFromLresult = 
    (LPFNOBJECTFROMLRESULT)::GetProcAddress(hInst, "ObjectFromLresult"); 
if (pfObjectFromLresult != NULL) 
{ 
    HRESULT hr; 
    hr = (*pfObjectFromLresult)(lRes, IID_IHTMLDocument, 0, (void**)&pDoc); 
    if (SUCCEEDED(hr)) { 
     IServiceProvider *pService; 
     hr = pDoc->QueryInterface(IID_IServiceProvider, (void **) &pService); 
     if (SUCCEEDED(hr)) 
     { 
      hr = pService->QueryService(SID_SWebBrowserApp, 
       IID_IWebBrowser2, (void **) &pBrowser); 

      // This is where the problem occurs: 
      // hr == E_NOINTERFACE 
     } 
    } 
} 

В случае, если это имеет значение, это Виста и IE8. (Я подчеркиваю это, потому что оба из них вносили изменения в мою кодовую базу, которая отлично работала с XP/IE7.)

Опять же, моя цель - получить каждый IHTMLElement и взаимодействовать с ним. У меня нет доступа к исходному коду приложения, которое я автоматизирую.

Я рассматриваю отправки нажатий клавиш вслепую в Internet Explorer_Server окне, но не хотелось бы.

Edited добавить:

Кто-то предложил получать дочерние окна и отправлять им сообщения, но я уверен, что не работает с Internet Explorer_Server; согласно Spy ++, нет никаких дочерних окон. (Это не IE-специфичны. Java-апплеты, кажется, не имеют дочерние окна, либо.)

Update

В комментариях, Саймон Maurer сказал выше код работал на него, и просто убедитесь, что нет опечаток, он очень щедро разместил полное автономное приложение на pastebin. Когда я использовал свой код, он не так же, как в том же месте, и я понял, что он думал, что я хотел подключиться к странице основного, а не в выпадающем меню. Поэтому я отредактировал текст выше, чтобы удалить эту двусмысленность.

+0

В чем исключение? Действительно ли 'pDoc' выглядит действительным, когда вы вызываете' pDoc-> QueryInterface'? –

+0

@NateHekman: Я существенно пересмотрел вопрос. – egrunin

+0

Можете ли вы подтвердить, что приложение C++ не работает? Что такое «диалог веб-страницы»? Это окно IE появляется, когда скрипт вызывает showModalDialog? –

ответ

3

Я не знаю, почему вы хотите получить IServiceProvider или IWebBrowser2, если вы просто хотите IHTMLElement. Вы можете получить их, вызвав метод IHTMLDocumentget_all().

Этот фрагмент кода показывает, как это работает:

#include <Windows.h> 
#include <mshtml.h> 
#include <Exdisp.h> 
#include <atlbase.h> 
#include <SHLGUID.h> 
#include <oleacc.h> 
#include <comdef.h> 
#include <tchar.h> 

HRESULT EnumElements(HINSTANCE hOleAccInst, HWND child) 
{ 
    HRESULT hr; 

    UINT nMsg = ::RegisterWindowMessage(_T("WM_HTML_GETOBJECT")); 
    LRESULT lRes = 0; 
    ::SendMessageTimeout(child, nMsg, 0L, 0L, SMTO_ABORTIFHUNG, 1000, (PDWORD)&lRes); 

    LPFNOBJECTFROMLRESULT pfObjectFromLresult = (LPFNOBJECTFROMLRESULT)::GetProcAddress(hOleAccInst, "ObjectFromLresult"); 
    if (pfObjectFromLresult == NULL) 
     return S_FALSE; 

    CComPtr<IHTMLDocument2> spDoc; 
    hr = (*pfObjectFromLresult)(lRes, IID_IHTMLDocument2, 0, (void**)&spDoc); 
    if (FAILED(hr)) return hr; 

    CComPtr<IHTMLElementCollection> spElementCollection; 
    hr = spDoc->get_all(&spElementCollection); 
    if (FAILED(hr)) return hr; 

    CComBSTR url; 
    spDoc->get_URL(&url); 
    printf("URL: %ws\n", url); 

    long lElementCount; 
    hr = spElementCollection->get_length(&lElementCount); 
    if (FAILED(hr)) return hr; 
    printf("Number of elements: %d", lElementCount); 

    VARIANT vIndex; vIndex.vt = VT_I4; 
    VARIANT vSubIndex; vSubIndex.vt = VT_I4; vSubIndex.lVal = 0; 
    for (vIndex.lVal = 0; vIndex.lVal < lElementCount; vIndex.lVal++) 
    { 
     CComPtr<IDispatch> spDispatchElement; 
     if (FAILED(spElementCollection->item(vIndex, vSubIndex, &spDispatchElement))) 
      continue; 
     CComPtr<IHTMLElement> spElement; 
     if (FAILED(spDispatchElement->QueryInterface(IID_IHTMLElement, (void**)&spElement))) 
      continue; 
     CComBSTR tagName; 
     if (SUCCEEDED(spElement->get_tagName(&tagName))) 
     { 
      printf("%ws\n", tagName); 
     } 
    } 
    return S_OK; 
} 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    ::CoInitialize(NULL); 
    HINSTANCE hInst = ::LoadLibrary(_T("OLEACC.DLL")); 
    if (hInst != NULL) 
    { 
     HRESULT hr = EnumElements(hInst, (HWND)0x000F05E4); // Handle to Internet Explorer_Server determined with Spy++ :) 
     ::FreeLibrary(hInst); 
    } 
    ::CoUninitialize(); 
    return 0; 
} 

Приведенный выше код работает на обоих: нормальное окно или модальное окно, просто передать правильный HWND функции SendMessageTimeout.

ПРЕДУПРЕЖДЕНИЕ Я использую HWND значение жестко закодировано в данном примере, если вы хотите, чтобы проверить его, вы должны запустить экземпляр IE и получить HWND в Internet Explorer_Server окна с помощью Spy ++.

Я также рекомендую использовать CComPtr во избежание утечек памяти.

+0

Я попробую это. Какие версии IE вы используете? – egrunin

+0

IE10 на Windows 7 x64 –

+0

IE8 на Windows XP 32bit также работает –

 Смежные вопросы

  • Нет связанных вопросов^_^