下沉DWebBrowserEvent2的活动挂导航(Sinking Events of DWebBr

2019-06-27 16:30发布

我就像JimEvans问题凿井DWebBrowserEvents2事件似乎挂起程序的导航 ,但我不明白的anwser,有人可以告诉我更多地了解它?

我被状子C ++操纵IE浏览器。 有些代码是从CodeProject上复制。 但是,当我处理活动我的IE得到了挂,我的主要功能完成之前,我不能让DISPID_NAVIGETCOMPLETE事件。

我下面的代码:

#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\n", dwStatusCode);
    break;
    }
case DISPID_NAVIGATECOMPLETE2:
    printf("Navigate Complete!\n");
    break;

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

default:
    //MessageBox(NULL, L"A Message", NULL, NULL);
    printf("A Message !\n the dispIdMemberis %d\n", 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\n", a);

m_pConnectionPoint->Unadvise(m_dwCookie);

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

CoUninitialize();
}

Answer 1:

这个问题,答案在那边你是指,即将与您的活动的线程处理窗口消息的问题,所谓的“消息泵”。 你做:

Sleep(20000);

这就是问题的原因。 相反,你应该等待,你应该处理窗口消息在等待。 应该改为与调度这样的消息循环:

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

使该窗口的消息IECOM可能已经张贴处理您的请求的一部分,将到达目标窗口,并会进行处理。 相反,你都锁定线程给它没有选择做自己应该做的。 上述循环仅调度信息一次,然而,如果你需要超时,你可以做到这一点作为一个无限循环在处理成功或失败的一些指示醒来,或基于事件的消息循环,在唤醒一个消息,并落回到睡眠而不浪费否则CPU周期。

也就是说,你的Sleep ,持续20秒仍在处理窗口消息可能是这个(代码段应该是很好的更换复制/粘贴):

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\n"), 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\n"), Message.hwnd, Message.message);
        TranslateMessage(&Message);
        DispatchMessage(&Message);
    }
}
CloseHandle(hFakeEvent);


文章来源: Sinking Events of DWebBrowserEvent2 hangs the navigation