How to extend CAxHostWindow?

霸气de小男生 提交于 2019-12-14 01:28:48

问题


Standard class CAxHostWindow that used by ATL for COM ActiveX hosting does not support interface IDocHostUIHandler2. How can i to extend CAxHostWindow class for IDocHostUIHandler2 supporting?


回答1:


Actually, there's a way to customize CAxHostWindow without modifying it. E.g, I wanted to implement IOleCommandTarget on the client site object. The tricky part was to override the creation of the host window. Here's how it can be done:

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
  // ...

}

Here's how to use it:

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;



回答2:


CAxHostWindow class is available in source code. So you can:

  1. Edit or duplicate class and add the interface right there
  2. You can aggregate the class via COM aggregation into your own, which adds support for IDocHostUIHandler2 - in which case you don't need source edits, but source code is still a great guide leading you on the way; or you can possibly even inherit from it.

The #2 solution is cleaner in terms of not touching ATL code itself, however you will have to also resolve instantiation problem. The class is not COM creatable, it is created through ATL creator class. You will have to take care of this as well, e.g. by providing your alternate option for AtlAxAttachControl function.



来源:https://stackoverflow.com/questions/18329836/how-to-extend-caxhostwindow

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!