Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
372 views
in Technique[技术] by (71.8m points)

internet explorer - Sinking Events of DWebBrowserEvent2 hangs the navigation

I have a problem just like JimEvans in Sinking DWebBrowserEvents2 events appears to hang programmatic navigation but I can't understand the anwser, can somebody tell me more about it??

I'm manipulating the IE Explorer by plaint C++. Some codes are copied from the Codeproject. But my IE got hung when I'm handling the Events, and I can't get the DISPID_NAVIGETCOMPLETE event before my main function finishes.

My code below:

#include <afxwin.h>
#include <afxdisp.h>
#include <iostream>
#include <MsHTML.h>
#include <Exdisp.h>
#include <ExDispid.h>

class IE_Events_Sinker : public DWebBrowserEvents2
{

public:
// No constructor or destructor is needed
// IUnknown methods
STDMETHODIMP QueryInterface(REFIID riid,void **ppvObject);
STDMETHODIMP_(ULONG) AddRef();
STDMETHODIMP_(ULONG) Release();
// IDispatch methods
STDMETHODIMP GetTypeInfoCount(UINT *pctinfo);
STDMETHODIMP GetTypeInfo(UINT iTInfo,LCID lcid,ITypeInfo **ppTInfo);
STDMETHODIMP GetIDsOfNames(REFIID riid,LPOLESTR *rgszNames,UINT cNames,LCID lcid,DISPID *rgDispId);
STDMETHODIMP Invoke(DISPID dispIdMember,REFIID riid,LCID lcid,WORD wFlags,
    DISPPARAMS *pDispParams,VARIANT *pVarResult,EXCEPINFO *pExcepInfo,UINT   *puArgErr);
};

IE_Events_Sinker IESinker;

STDMETHODIMP IE_Events_Sinker::Invoke(DISPID dispIdMember, 
    REFIID riid, 
    LCID lcid, 
    WORD wFlags, 
    DISPPARAMS FAR* pDispParams, 
    VARIANT FAR* pVarResult, 
    EXCEPINFO FAR* pExcepInfo, 
    unsigned int FAR* puArgErr )
{
switch(dispIdMember)
{
case DISPID_NAVIGATEERROR:
    {
    //Extract the status code from the DISPPARAMS structure
    VARIANT * vt_statuscode = pDispParams->rgvarg[1].pvarVal;
    DWORD  dwStatusCode =  vt_statuscode->lVal;
    //Extract the event's IDispatch pointer
    IDispatch *pdispFiredEvent = pDispParams->rgvarg[4].pdispVal;
    printf("Status Code: %d
", dwStatusCode);
    break;
    }
case DISPID_NAVIGATECOMPLETE2:
    printf("Navigate Complete!
");
    break;

case DISPID_BEFORENAVIGATE2:
    printf("Before Navigate is fired!
");
    break;

default:
    //MessageBox(NULL, L"A Message", NULL, NULL);
    printf("A Message !
 the dispIdMemberis %d
", dispIdMember);
    break;
}

return S_OK;
}

STDMETHODIMP IE_Events_Sinker::QueryInterface(REFIID riid,void **ppvObject)
{
// Check if ppvObject is a valid pointer
if(IsBadWritePtr(ppvObject,sizeof(void*))) return E_POINTER;
// Set *ppvObject to NULL
(*ppvObject)=NULL;
// See if the requested IID matches one that we support
// If it doesn't return E_NOINTERFACE
if(!IsEqualIID(riid,IID_IUnknown) && !IsEqualIID(riid,IID_IDispatch) && !IsEqualIID(riid,DIID_DWebBrowserEvents2)) return E_NOINTERFACE;
// If it's a matching IID, set *ppvObject to point to the global EventSink object
(*ppvObject)=(void*)&IESinker;
return S_OK;
}

STDMETHODIMP_(ULONG) IE_Events_Sinker::AddRef()
{
return 1; // We always have just one static object
}

STDMETHODIMP_(ULONG) IE_Events_Sinker::Release()
{
return 1; // Ditto
}

// We don't need to implement the next three methods because we are just a pure event sink
// We only care about Invoke() which is what IE calls to notify us of events

STDMETHODIMP IE_Events_Sinker::GetTypeInfoCount(UINT *pctinfo)
{
UNREFERENCED_PARAMETER(pctinfo);

return E_NOTIMPL;
}

STDMETHODIMP IE_Events_Sinker::GetTypeInfo(UINT iTInfo,LCID lcid,ITypeInfo **ppTInfo)
{
UNREFERENCED_PARAMETER(iTInfo);
UNREFERENCED_PARAMETER(lcid);
UNREFERENCED_PARAMETER(ppTInfo);

return E_NOTIMPL;
}

STDMETHODIMP IE_Events_Sinker::GetIDsOfNames(REFIID riid,LPOLESTR *rgszNames,UINT     cNames,LCID lcid,DISPID *rgDispId)
{
UNREFERENCED_PARAMETER(riid);
UNREFERENCED_PARAMETER(rgszNames);
UNREFERENCED_PARAMETER(cNames);
UNREFERENCED_PARAMETER(lcid);
UNREFERENCED_PARAMETER(rgDispId);

return E_NOTIMPL;
}

int main()
{
HRESULT hr;
IWebBrowser2* IWbr;

IConnectionPointContainer* pCPContainer;
IConnectionPoint* m_pConnectionPoint;

CoInitialize(NULL);

//hr = CoCreateInstance(CLSID_InternetExplorer, NULL, CLSCTX_LOCAL_SERVER, IID_IWebBrowser2, (void**)&IWbr);
hr = CoCreateInstance(CLSID_InternetExplorer, NULL, CLSCTX_LOCAL_SERVER, IID_IWebBrowser2, (void**)&IWbr);
IWbr->put_Visible(TRUE);

hr = IWbr->QueryInterface(IID_IConnectionPointContainer, (void**)&pCPContainer);

hr = pCPContainer->FindConnectionPoint(DIID_DWebBrowserEvents2, &m_pConnectionPoint);

//Important Point!
DWORD m_dwCookie;
m_pConnectionPoint->Advise(&IESinker, &m_dwCookie);

COleVariant vtEmpty;
BSTR url2 = SysAllocString(L"http://www.qq.com/");
IWbr->Navigate(url2, &vtEmpty, &vtEmpty, &vtEmpty, &vtEmpty);

Sleep(20000);
//hr = IWbr->Quit();
//while(FAILED(hr))
//{
    //a++;
    //hr = IWbr->Quit();
//}
//printf("shut down %d times
", a);

m_pConnectionPoint->Unadvise(m_dwCookie);

m_pConnectionPoint->Release();
IWbr->Release();
pCPContainer->Release();

CoUninitialize();
}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

The problem, and the answer over there in the question you are referring to, is about processing window messages on the thread with your activity, so called "message pump". You do:

Sleep(20000);

And this is the cause of the problem. Instead you should be waiting AND you should be processing window messages while waiting. It should instead be a loop with dispatching messages like this:

MSG Message;
while(PeekMessage(&Message, NULL, WM_NULL, WM_NULL, PM_REMOVE))
{
    TranslateMessage(&Message);
    DispatchMessage(&Message);
}

So that window messages that IE or COM could have posted as a part of processing your request, would reach the target windows and would be handled. Instead you are locking the thread giving it no option to do what it should do. The loop above only dispatches messages once, however, so if you need a timeout, you could do it as an infinite loop waking up on some indication of success or failure in processing, or a event-an-message based loop that wakes up on a message and falls back sleeping without wasting CPU cycles otherwise.

That is, your Sleep for 20 seconds still processing window messages could have been this (the snippet should be good for copy/pasting for replacement):

const ULONG nTimeoutTime = GetTickCount() + 20 * 1000; // In 20 seconds
const HANDLE hFakeEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
for(; ; )
{
    const LONG nWaitTime = nTimeoutTime - GetTickCount();
    if(nWaitTime <= 0)
        break; // Timeout
    const DWORD nWaitResult = MsgWaitForMultipleObjects(1, &hFakeEvent, FALSE, nWaitTime, QS_ALLINPUT | QS_ALLPOSTMESSAGE);
    //ATLTRACE(_T("nWaitResult 0x%x
"), nWaitResult);
    //ATLASSERT(nWaitResult == WAIT_OBJECT_0 + 1 || nWaitResult == WAIT_TIMEOUT);
    if(nWaitResult == WAIT_TIMEOUT)
        break; // Timeout
    MSG Message;
    while(PeekMessage(&Message, NULL, WM_NULL, WM_NULL, PM_REMOVE))
    {
        //ATLTRACE(_T("Message.hwnd 0x%p, Message.message 0x%04x
"), Message.hwnd, Message.message);
        TranslateMessage(&Message);
        DispatchMessage(&Message);
    }
}
CloseHandle(hFakeEvent);

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...