问题
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:
- Edit or duplicate class and add the interface right there
- 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