如何在MFC中获取嵌入式Web浏览器控件的HWND

时间:2015-04-16 02:21:22

标签: c++ windows internet-explorer winapi mfc

我在基于对话框的MFC窗口中使用嵌入式web browser control,我需要知道其中的Web浏览器控件的HWND。我能够找到声称检索它的以下代码:

HWND hWndWebBrowser = NULL;

LPUNKNOWN unknown = m_browser.GetControlUnknown();

IWebBrowser2* pWB = NULL;
if(SUCCEEDED(unknown->QueryInterface(IID_IWebBrowser2,(void **)&pWB)))
{
    CComPtr<IServiceProvider> pServiceProvider;
    if (SUCCEEDED(pWB->QueryInterface(IID_IServiceProvider, (void**)&pServiceProvider)))
    {
        CComPtr<IOleWindow> pWindow;
        if (SUCCEEDED(pServiceProvider->QueryService(SID_SShellBrowser, IID_IOleWindow, (void**)&pWindow)))
        {
            SHANDLE_PTR hBrowser = 0;
            if (SUCCEEDED(pWindow->GetWindow(&hBrowser)))
            {
                hWndWebBrowser = (HWND)hBrowser;
            }
        }
    }
}

if(unknown)
{
    unknown->Release();
}

但问题是,当它运行时,它返回一个句柄,但不是我期望的句柄。说明它的最好方法是使用这个Spy ++截图:

enter image description here

我知道我可以使用EnumChildWindows并查找包含Internet Explorer_Server类的窗口,但我有点担心使用此未记录的类名。

有没有人有更好的方法来检索该(Web浏览器)窗口句柄?

3 个答案:

答案 0 :(得分:1)

Obtaining the HWND for the WebBrowser control。您可以使用以下函数来检索HWND。

IOleWindow *pOWin;
HWND hBWnd;

HRESULT hRes = m_pBrowserApp->QueryInterface(IID_IOleWindow, (void **)&pOWin);
if (SUCCEEDED(hRes)) {
    hRes = pOWin->GetWindow(&hBWnd);
    if (SUCCEEDED(hRes)) {
        // Place hBWnd-manipulating code here
    }
}   

答案 1 :(得分:1)

这个问题的词汇有点棘手。

(Web浏览器)的HWND确实是答案 你发布的帖子和Santosh Dhanawade发布的答案。

加载文档后,Web浏览器控件会创建一个 新窗口或iframe,请参阅DWebBrowserEvents2::DocumentComplete事件。

  

事件处理程序参数:
  “ pDisp [in]

     

指向加载文档的窗口或框架的IDispatch接口的指针。可以为IWebBrowser2接口查询此IDispatch接口。

所以,改变问题:

“有没有人有更好的方法来检索(网络浏览器)窗口句柄?”

为:

“有没有人有更好的方法来检索(窗口或iframe )窗口句柄?”

我们有你要锁定的窗口或iframe HWND, 在文件加载完毕后将可以使用。

这意味着我们可以执行以下操作:

实现DocumentComplete事件处理程序抛出原始c或c ++实现 IDispatch或ATL DispEventImpl或ATL DispEventSimpleImpl。 请参阅Understanding COM Event Handling

将我们的事件处理程序接收到Web浏览器控件中以获取事件报告。

从DocumentComplete事件中获取窗口或iframe HWND:

假设原始c ++ IDispatch实现:

IFACEMETHODIMP DWebBrowserEvents2Impl::Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS * pDispParams, VARIANT * pVarResult, EXCEPINFO * pExcepInfo, UINT * puArgErr)
{
    if (dispIdMember == DISPID_DOCUMENTCOMPLETE) {
        VARIANT variantDispatch;
        VariantInit(&variantDispatch);
        HRESULT hr = DispGetParam(pDispParams, 0, VT_DISPATCH, &variantDispatch, NULL);
        if (SUCCEEDED(hr)) {            
            IOleWindow* iOleWindow;
            hr = variantDispatch.pdispVal->QueryInterface(IID_IOleWindow, (LPVOID*) &iOleWindow);
            if (SUCCEEDED(hr)) {
                HWND hwnd;
                hr = iOleWindow->GetWindow(&hwnd);
                iOleWindow->Release();
                if (SUCCEEED(hr)){
                //now the hwnd correponds to the Internet Explorer_Server window.
                //Do what ever you want with the HWND handler.              
                }  
            }           
        }
        return S_OK;
    }
    return E_NOTIMPL;
}

答案 2 :(得分:0)

根据我的经验,我们正在寻找的窗口是 CHtmlView 派生的 CWnd 的直接后代,所以我使用这个 hack 来获取窗口并将焦点设置到它:

static CWnd* findChildWebbrowser(CWnd* pWnd) {
    if(pWnd == NULL) { return NULL; }
    CWnd* pC = pWnd->GetWindow(GW_CHILD);
    if(pC == NULL) { return NULL; };
    CString buf;
    ::GetClassName(pC->GetSafeHwnd(), buf.GetBuffer(2048), 2047);
    buf.ReleaseBuffer();
    if(buf == _T("Internet Explorer_Server")) {
        return pC;
    }
    return findChildWebbrowser(pC);
}

void CMyWebView::OnSetFocus(CWnd* pOldWnd) {
    // CHtmlView::OnSetFocus(pOldWnd);
    CWnd* pIE = findChildWebbrowser(this);
    if(pIE!=NULL) {
        // this makes cursor/page keys work
        pIE->SetFocus();
        // this makes the TAB key work
        pIE->SendMessage(WM_LBUTTONDOWN);
        pIE->SendMessage(WM_LBUTTONUP);
    }
}