3

ATL 用于 COM ActiveX 宿主的标准类 CAxHostWindow 不支持接口 IDocHostUIHandler2。如何扩展 CAxHostWindow 类以支持 IDocHostUIHandler2?

4

2 回答 2

2

实际上,有一种方法可以在CAxHostWindow不修改的情况下进行自定义。例如,我想IOleCommandTarget在客户端站点对象上实现。棘手的部分是覆盖主机窗口的创建。这是如何完成的:

class ATL_NO_VTABLE CWebBrowserHost :
  public CAxHostWindow,
  public IOleCommandTarget
{
public:
  static CWndClassInfo& GetWndClassInfo()
  {
    static CWndClassInfo wc =
    {
      { sizeof(WNDCLASSEX), 0, StartWindowProc,
        0, 0, 0, 0, 0, (HBRUSH)(COLOR_WINDOW + 1), 0, NULL, 0 },
      NULL, NULL, IDC_ARROW, TRUE, 0, _T("")
    };
    return wc;
  }

  DECLARE_PROTECT_FINAL_CONSTRUCT()

  DECLARE_NO_REGISTRY()
  DECLARE_POLY_AGGREGATABLE(CWebBrowserHost)
  DECLARE_GET_CONTROLLING_UNKNOWN()

  BEGIN_COM_MAP(CWebBrowserHost)
    COM_INTERFACE_ENTRY(IDocHostUIHandler)
    COM_INTERFACE_ENTRY(IOleCommandTarget)
    COM_INTERFACE_ENTRY_CHAIN(CAxHostWindow)
  END_COM_MAP()

  HWND Create(
    _In_opt_ HWND hWndParent,
    _In_ _U_RECT rect = NULL,
    _In_opt_z_ LPCTSTR szWindowName = NULL,
    _In_ DWORD dwStyle = 0,
    _In_ DWORD dwExStyle = 0,
    _In_ _U_MENUorID MenuOrID = 0U,
    _In_opt_ LPVOID lpCreateParam = NULL)
  {
    ATOM atom = GetWndClassInfo().Register(&m_pfnSuperWindowProc);
    if (!atom)
      return NULL;

    // Allocate the thunk structure here, where we can fail gracefully.
    BOOL result = m_thunk.Init(NULL,NULL);
    if (result == FALSE)
    {
      SetLastError(ERROR_OUTOFMEMORY);
      return NULL;
    }

    _AtlWinModule.AddCreateWndData(&m_thunk.cd, this);

    dwStyle = GetWndStyle(dwStyle);
    dwExStyle = GetWndExStyle(dwExStyle);

    // set caption
    if (szWindowName == NULL)
      szWindowName = GetWndCaption();

    return CWindow::Create((LPCTSTR)atom, hWndParent, rect, szWindowName, dwStyle, dwExStyle, MenuOrID, lpCreateParam);
  }

  // IOleCommandTarget methods
  // ...

}

以下是如何使用它:

CComPtr<CWebBrowserHost> m_webBrowserHost;

//...

// Create a child AX host window. 
CComObject<CWebBrowserHost>* pHost = NULL;
hr = CComObject<CWebBrowserHost>::CreateInstance(&pHost);
if (FAILED(hr))
  return 0;
m_webBrowserHost = pHost;

RECT rect;
GetClientRect(&rect);
m_webBrowserHost->Create(m_hWnd, rect, NULL, WS_CHILD | WS_VISIBLE);
if (m_webBrowserHost->m_hWnd == NULL)
  return 0;

// Create WebBrowser control
CComPtr<IUnknown> spControl;
hr = pHost->CreateControlEx(
  OLESTR("{8856F961-340A-11D0-A96B-00C04FD705A2}"), // WebBrowser Control CLSID
  m_webBrowserHost->m_hWnd, 
  NULL,
  &spControl, 
  DIID_DWebBrowserEvents2, 
  ((IUnknown*)(IDispEventImpl<1, CMainWindow, &DIID_DWebBrowserEvents2, &LIBID_SHDocVw, 0xFFFF, 0xFFFF>*)this)
);

if (FAILED(hr))
  return 0;
于 2013-08-20T12:15:46.277 回答
1

CAxHostWindow类在源代码中可用。这样你就可以:

  1. 编辑或复制类并在此处添加界面
  2. 您可以通过COM 聚合将类聚合到您自己的类中,这增加了对IDocHostUIHandler2- 在这种情况下您不需要源代码编辑的支持,但源代码仍然是引导您前进的绝佳指南;或者你甚至可以继承它。

#2 解决方案在不触及 ATL 代码本身方面更简洁,但是您还必须解决实例化问题。该类不是 COM 创建的,它是通过 ATL 创建者类创建的。您还必须注意这一点,例如通过提供您的替代AtlAxAttachControl功能选项。

于 2013-08-20T08:22:30.543 回答