2013-04-17 6 views
11

एक आईई वेबैप स्वचालित करने के लिए कैसे एक मोडल HTML संवाद पॉप?

मैं एक सी ++ प्रोग्राम है जो एक वेबसाइट से इंटरैक्ट है [एक बार फिर स्पष्टता के लिए संशोधित]। साइट आईई-विशिष्ट है, और मेरा कार्यक्रम भी है।

मैं आईई के चल रहे उदाहरण को सामान्य तरीके से कनेक्ट कर रहा हूं (प्रक्रिया से बाहर - कोड देखें)। एक बार मुझे IWebBrowser2 मिल जाए, मुझे IHTMLDocument2 प्राप्त करने में कोई समस्या नहीं है और व्यक्तिगत IHTMLElement ऑब्जेक्ट्स के साथ बातचीत कर रहे हैं, फ़ील्ड भरकर और बटन क्लिक कर रहे हैं।

लेकिन यदि वेब पेज में जावास्क्रिप्ट है जो window.showModalDialog पर कॉल करता है, तो मैं अटक गया हूं: मुझे अन्य पृष्ठों की तरह पॉपअप में HTML तत्वों से बातचीत करने की आवश्यकता है; लेकिन मुझे लगता है कि यह IWebBrowser2 नहीं है।

पॉपअप को हमेशा "वेब पेज संवाद" शीर्षक दिया जाता है, और Internet Explorer_TridentDlgFrame प्रकार की एक विंडो है जिसमें Internet Explorer_Server है। लेकिन मुझे IWebBrowser2 Internet Explorer_Server विंडो से नहीं मिल सकता है जब मैं एक सामान्य आईई उदाहरण हो सकता हूं।

मैं IHTMLDocument2Ptr प्राप्त कर सकते हैं, लेकिन जब मैं IWebBrowser2 प्राप्त करने की कोशिश मैं E_NOINTERFACE के HRESULT मिलता है।

कोड सुंदर मानक सामान है, और ठीक काम करता है अगर यह एक 'सामान्य' 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 विंडो पर अंधेरे से कीस्ट्रोक भेजने पर विचार कर रहा हूं, लेकिन इसके बजाय नहीं।

संपादित जोड़ने के लिए:

किसी बच्चे खिड़कियों हो रही है और उन्हें संदेश भेजने का सुझाव दिया है, लेकिन मैं बहुत यकीन है कि Internet Explorer_Server साथ काम नहीं करता हूँ, जासूस ++ के अनुसार, कोई भी बच्चा खिड़कियां नहीं हैं। (यह IE-विशिष्ट नहीं है। जावा एप्लेट बच्चे खिड़कियों के लिए जगह है, या तो नहीं है।)

अद्यतन

टिप्पणियों में, साइमन Maurer ऊपर कोड उसके लिए काम, और बस से कहा सुनिश्चित करें कि कोई टाइपो नहीं था, उन्होंने pastebin पर एक पूर्ण स्टैंडअलोन ऐप पोस्ट किया। जब मैंने अपना कोड इस्तेमाल किया, तो यह उसी स्थान पर उसी तरह विफल रहा, और मुझे एहसास हुआ कि उसने सोचा था कि मैं पृष्ठ के अंतर्गत कनेक्ट करना चाहता था, पॉपअप नहीं। तो मैंने उस अस्पष्टता को दूर करने के लिए ऊपर दिए गए पाठ को संपादित किया है।

+0

अपवाद क्या है? जब आप 'pDoc-> QueryInterface' को कॉल करते हैं तो' pDoc' मान्य दिखता है? –

+0

@NateHekman: मैंने इस सवाल को काफी संशोधित किया है। – egrunin

+0

क्या आप पुष्टि कर सकते हैं कि सी ++ ऐप प्रक्रिया से बाहर है? "वेबपृष्ठ संवाद" क्या है? क्या यह आईई विंडो है जो एक स्क्रिप्ट कॉल करता है जब मॉड्यूलडियलॉग? –

उत्तर

3

मुझे नहीं पता कि आप IServiceProvider या IWebBrowser2 क्यों प्राप्त करना चाहते हैं यदि आप केवल IHTMLElement के हैं। आप IHTMLDocument की get_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; 
} 

कोड से ऊपर दोनों पर काम करता है: एक सामान्य विंडो या मोडल विंडो, बस SendMessageTimeout कार्य करने के लिए सही HWND गुजरती हैं।

चेतावनी मैं इस उदाहरण में एक हार्ड-कोडेड HWND मान का उपयोग, आप इसे परीक्षण करने के लिए आप एक IE उदाहरण शुरू करने और जासूसी का उपयोग कर ++ Internet Explorer_Server विंडो के HWND मिलना चाहिए चाहते हैं।

मैं आपको मेमोरी लीक से बचने के लिए CComPtr का उपयोग करने की सलाह देता हूं।

+0

मैं इसे आजमाउंगा। आप IE का किस संस्करण का उपयोग कर रहे हैं? विंडोज़ XP पर – egrunin

+0

आईई 10 विंडोज 7 एक्स 64 –

+0

आईई 8 विंडोज एक्सपी 32 बिट पर भी काम करता है –

संबंधित मुद्दे