CAxHostWindow and CAxWindow

[Previous] [Next]

Sometimes you want to create a user interface that dynamically includes an ActiveX control in a window, not a dialog box. You might want to specify the type of control at run time as well. ATL supports control containment in a window through its ActiveX hosting window classes, CAxHostWindow and CAxWindow.


Hosting an ActiveX control involves a lot of interfaces, for which ATL provides default implementations in CAxHostWindow. CAxHostWindow is found in ATLHOST.H and has the following class declaration:

 class ATL_NO_VTABLE CAxHostWindow :      public CComCoClass<CAxHostWindow , &CLSID_NULL>,     public CComObjectRootEx<CComSingleThreadModel>,     public CWindowImpl<CAxHostWindow>,     public IAxWinHostWindow,     public IOleClientSite,     public IOleInPlaceSiteWindowless,     public IOleControlSite,     public IOleContainer,     public IObjectWithSiteImpl<CAxHostWindow>,     public IServiceProvider,     public IAdviseSink, #ifndef _ATL_NO_DOCHOSTUIHANDLER     public IDocHostUIHandler, #endif     public IDispatchImpl<IAxWinAmbientDispatch,         &IID_IAxWinAmbientDispatch, &LIBID_ATLLib> 

This isn't your average window implementation. CAxHostWindow is both a COM object and a window implementation that can host an ActiveX control. The idea is that ATL registers a window class AtlAxWin when you call the global function AtlAxWinInit. You can then create a window by using the standard Win32 CreateWindow function, as shown here:

 AtlAxWinInit(); // Create a window that will be subclassed by CAxHostWindow. DWORD dwStyle = WS_CHILD | WS_VISIBLE; CRect rcBounds(GetBounds()); HWND hWnd = ::CreateWindow(_T("AtlAxWin"), NULL , dwStyle,     rcBounds.left,,      rcBounds.Width(), rcBounds.Height(),     hParent,      NULL,      ::GetModuleHandle(NULL),      NULL); 

When the ATL window procedure for the AtlAxWin class (AtlAxWindowProc) gets WM_CREATE, an instance of CAxHostWindow is created for you and your HWND is subclassed. You never actually create a CAxHostWindow on your own or derive a class from it. To create or load an ActiveX control in the window, you need to use the IAxWinHostWindow interface, which ATL defines in ATLIFACE.IDL and implements in CAxHostWindow. The interface provides methods to create the ActiveX control or attach an existing control instance. The interface IDL is shown here:

 interface IAxWinHostWindow : IUnknown {     HRESULT CreateControl([in] LPCOLESTR lpTricsData,         [in] HWND hWnd, [in] IStream* pStream);     HRESULT CreateControlEx([in] LPCOLESTR lpTricsData,         [in] HWND hWnd, [in] IStream* pStream,         [out]IUnknown** ppUnk, [in] REFIID riidAdvise,         [in]IUnknown* punkAdvise);     HRESULT AttachControl([in] IUnknown* pUnkControl,         [in] HWND hWnd);     HRESULT QueryControl([in] REFIID riid, [out,         iid_is(riid)] void **ppvObject);     HRESULT SetExternalDispatch([in] IDispatch* pDisp);     HRESULT SetExternalUIHandler(         [in] IDocHostUIHandlerDispatch* pDisp); }; 

Right now, all we have is an HWND for the window that we got back from CreateWindow, but we need an IAxWinHostWindow pointer for the CAxHostWindow object. AtlAxWinInit registers two window messages that we can use to get the IUnknown pointer for CAxHostWindow and the IUnknown pointer for the contained control after we create it. The messages are WM_ATLGETHOST and WM_ATLGETCONTROL. Both return IUnknown pointers in the LRESULT. (ATL increments the reference count before returning the pointers to you.) As a convenience, ATL provides a couple of global functions to get the relevant interface pointers using an HWND, as shown in the following code section from ATLHOST.H:

 ATLINLINE ATLAPI AtlAxGetControl(HWND h, IUnknown** pp) {     ATLASSERT(WM_ATLGETCONTROL != 0);     if(pp == NULL)         return E_POINTER;     *pp = (IUnknown*)SendMessage(h, WM_ATLGETCONTROL, 0, 0);     return (*pp) ? S_OK : E_FAIL; } ATLINLINE ATLAPI AtlAxGetHost(HWND h, IUnknown** pp) {     ATLASSERT(WM_ATLGETHOST != 0);     if(pp == NULL)         return E_POINTER;     *pp = (IUnknown*)SendMessage(h, WM_ATLGETHOST, 0, 0);     return (*pp) ? S_OK : E_FAIL; } 

Now we can get the IAxWinHostWindow pointer for the CAxHostWindow object and create a calendar control using this code:

 CComPtr<IUnknown> spUnk; HRESULT hr = AtlAxGetHost(hWnd, &spUnk); if(SUCCEEDED(hr)) {     CComQIPtr<IAxWinHostWindow> spAxWin(spUnk);     hr = spAxWin->CreateControl(L"MSCal.Calendar", hWnd, NULL); } 

The string that describes the control can be a progID or a CLSID. You can also specify a URL or a raw HTML string prefixed with MSHTML: that results in the creation of the Web browser control. ATL determines what type of string you've passed in to CreateControl and reacts accordingly. The ATLCON sample that ships with ATL is a useful test project for these various different description types.

The last parameter to CreateControl is an IStream pointer. If you specify a non-null value, the control is loaded from that stream using IPersistStreamInit on the control. CreateControlEx takes an additional parameter for an advise sink interface pointer in case you need to handle events from the control.

CAxHostWindow also implements a dual interface named IAxWinAmbientDispatch, which provides get and set methods for most of the common ambient properties, such as BackColor, Font, and UserMode. The ambient property states are maintained in CAxHostWindow data members. You use AtlAxGetHost to retrieve the host IUnknown pointer and then call QueryInterface for IAxWinAmbientDispatch, which you use to set or get ambient properties based on your application preferences.


CAxWindow encapsulates some of the code used in the previous section to manipulate a CAxHostWindow. Instead of creating a window using the Win32 API and the AtlAxWin class, simply instantiate a CAxWindow and call its Create member, which does essentially the same thing. To get any interface implemented by the CAxHostWindow object, use CAxWindow::QueryHost, which uses pretty much the same AtlAxGetHost code we used earlier. Here's the CAxWindow implementation:

 HRESULT QueryHost(REFIID iid, void** ppUnk) {     ATLASSERT(ppUnk != NULL);     HRESULT hr;     *ppUnk = NULL;     CComPtr<IUnknown> spUnk;     hr = AtlAxGetHost(m_hWnd, &spUnk);     if(SUCCEEDED(hr))         hr = spUnk->QueryInterface(iid, ppUnk);     return hr; } 

To create a control, use QueryHost to get an IAxWinHostWindow interface pointer, and then call its CreateControl method. Here's an example of how to create a control using CAxWindow:

 CAxWindow m_AxWindow; m_AxWindow.Create(hwndParent, ...); CComPtr<IAxWinHostWindow> spHost; m_AxWindow.QueryHost(&spHost); hr = spHost->CreateControl(L"MSCal.Calendar", m_AxWindow, NULL); 

Once created, any interface implemented by the contained control is available through CAxWindow::QueryControl. QueryControl uses the global AtlAxGetControl function we looked at earlier, but it also calls QueryInterface for us to get our desired interface pointer.

Inside Atl
Inside ATL (Programming Languages/C)
ISBN: 1572318589
EAN: 2147483647
Year: 1998
Pages: 127 © 2008-2017.
If you may any questions please contact us: