【问题标题】:How to get HWND of an embedded web browser control in MFC如何在 MFC 中获取嵌入式 Web 浏览器控件的 HWND
【发布时间】:2015-06-22 05:50:46
【问题描述】:

我在基于对话框的 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++ 屏幕截图:

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

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

【问题讨论】:

  • 听起来有点像 XY 问题。为什么需要那个特定的 HWND?是什么让它特别?因为这可能是你答案的关键。
  • 您担心使用类名吗?但是一旦你有了窗口句柄,你应该对你用那个窗口句柄做什么有完全相同的担忧。你打算用它做什么?
  • @DavidHeffernan:该句柄有多种合法用途。这是我头顶上的一个。我需要知道浏览器控件是否有键盘焦点(结果会影响弹出对话框中的选择)所以我这样做bool bHadFocus = ::GetFocus() == hIEWnd; 但要让它工作我需要知道hIEWnd
  • 不是我的意思。我的观点是,如果您担心跨版本的健壮性,那么即使您找到了窗口句柄,这些问题也会存在
  • @DavidHeffernan:是的,我听到了,但不太可能发生。我现在担心的是微软可能会逐步淘汰 IE,因此这个控件可能会有一个新的类名,比如Spartan_Server 之类的。

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


【解决方案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
    }
pOWin->Release(); // Missing from the MS example
}   

因为类名(Shell DocObject ViewInternet Explorer_Server)可能会发生变化,所以应该首选上面的代码,尽管考虑到 Internet Explorer 现已停产,这不太可能。

【讨论】:

  • 很抱歉,但它给我的结果与我上面的代码完全相同。
  • @c00000fd 你加了poWin-&gt;Release();吗?
【解决方案2】:

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

(Web Browser)的HWND确实是答案 您发布的内容和 Santosh Dhanawade 发布的答案。

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

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

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

所以,换个问题:

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

到:

“有没有人有更好的方法来检索那个(window or 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;
}

【讨论】:

    【解决方案3】:

    根据我的经验,我们正在寻找的窗口是 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);
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-03-17
      • 2010-09-08
      • 2010-12-05
      • 1970-01-01
      • 2010-10-23
      • 2011-02-12
      • 1970-01-01
      相关资源
      最近更新 更多