Click here to Skip to main content
Click here to Skip to main content

WTL Class for ActiveX Hosting

By , 6 Nov 2006
 

Introduction

WTL is the best library for Win32 Programming I have seen, simple and powerful. But sometimes during a period of time I have to change my mind and work with other libraries and tools, and then I forget some basic ATL/WTL concepts like:

  • Event Sink implementations
  • ActiveX instancing
  • Other basic hard-to-forget concepts

For this reason I'm developing a little library in a WTL like fashion that will help me, (and maybe someone out there), to make my life easier with WTL.

CWTLAxControl

This class and other related classes in this article will help you to make your job with ActiveX controls easier.

CWTLAxControl is a class that implements :

  • SmartPointer ( CComPtr<> ).
  • CWindowImpl<> ( CAxWindow ).
  • IDispEventImpl<>.

Maybe it seems to be a hard class to use , but wait a minute and take a look at the next IExplorer implementation, using this class you will have access to the IWebBrowser2 methods interface via "->" ( smart pointer ), window messages handling (Host window) and Sink Events events fired from ActiveX hosted to your own event handlers.

        
#define EVENTFN void __stdcall

class CWTLIExplorer : public CWTLAxControl<CWTLIExplorer,IWebBrowser2>
{
    public:
        // BEGIN_MSG_MAP() ... END_MSG_MAP() is optional
        
        BEGIN_MSG_MAP( CWTLIExplorer  )            
            MESSAGE_HANDLER(WM_CREATE,OnCreate) 
        END_MSG_MAP() 
        
        LRESULT OnCreate(UINT uMsg, WPARAM wParam , LPARAM lParam,
                BOOL& bHandled) 
        { 

            // First you must call CWTLAxControl<...,...>::OnCreate 
            // ( it set bHandled = true )

            return CWTLAxControl<CWTLIExplorer,IWebBrowser2,>::OnCreate(
                    uMsg, wParam, lParam, bHandled );
        }

        // SINK_ENTRY(...,...,...) is optional, BEGIN_SINK_MAP()
        // ... should be there

        BEGIN_SINK_MAP( CWTLIExplorer )
            SINK_ENTRY(0, DISPID_NAVIGATECOMPLETE2, OnNavigateComplete2 )
        END_SINK_MAP()
        
        EVENTFN OnNavigateComplete2( IDispatch* pDisp,  VARIANT* URL )
        {
            MessageBox( "OnNavigateComplete2" );
        }
};
        

Inside CWTLAxControl

Well, if you like the above implementation then it is time to get a more detailed view of how it works.

The first step is to take a look into the main parent class CWTLAxControl that looks like:

template <class T, class Interface>
class CWTLAxControl :    public CComPtr<Interface>,
            public CWindowImpl<CWTLAxControl,CAxWindow>, 
            public CWTLDispEventHelper<T,Interface>
{
    public:

    BEGIN_MSG_MAP(CWTLAxControl)
        MESSAGE_HANDLER(WM_CREATE, OnCreate)
    END_MSG_MAP()

    LRESULT OnCreate( UINT uMsg, WPARAM wParam , LPARAM lParam, 
           BOOL & bHandled )
    {
        LRESULT lRet;
        // We must call DefWindowProc before we can attach to the control.
        lRet = DefWindowProc( uMsg, wParam,lParam );
        // Get the Pointer to the control with Events (true)
        AttachControl(true);
        return lRet;
    }


    HRESULT AttachControl( BOOL bWithEvents = false ) 
    {
        HRESULT hr = S_OK;
        CComPtr<IUnknown> spUnk;
        // Get the IUnknown interface of control
        hr |= AtlAxGetControl( m_hWnd, &spUnk);

        if (SUCCEEDED(hr))
            // Query our interface
            hr |= spUnk->QueryInterface( __uuidof(Interface), 
                   (void**) (CComPtr<Interface>*)this);

        if ( bWithEvents && ! FAILED(hr) )
             // Start events
             hr|= EasyAdvise( spUnk );

        return hr;
    };
};
        

This class helps us to attach our CComPtr to the ActiveX control using the AttachControl method when it receives the WM_CREATE message. Furthermore this class is derived from CWindowImpl that give us the chance to handle all the windows messages that we'll need.

The last class CWTLDispEventHelper will help us to setup the correct IDispEventImpl implementation.

Inside CWTLDispEventHelper

This class will help us to setup the Event Sink for our control and looks like:
template <class T,class Interface>
class CWTLDispEventHelper : public IDispEventImpl<0,T>
{
    public:
                CComPtr<IUnknown> m_pUnk;
        
        HRESULT EasyAdvise(IUnknown* pUnk) 
        {  
            m_pUnk = pUnk;
            AtlGetObjectSourceInterface(pUnk,&m_libid, &m_iid, 
                 &m_wMajorVerNum, &m_wMinorVerNum);
            return DispEventAdvise(pUnk, &m_iid);
        }
        HRESULT EasyUnadvise() 
        { 
            AtlGetObjectSourceInterface(m_pUnk,&m_libid, 
                  &m_iid, &m_wMajorVerNum, &m_wMinorVerNum);
            return DispEventUnadvise(pUnk, &m_iid);
      }

};
        
It has only two methods EasyAdvise to setup the Event Sink handler and EasyUnadvise to deactivate it.

How to create the Control

Well, this is the easiest thing, the normal way we use to create any window in WTL:
[...]
CWTLIExplorer  m_pBrowser;
[...]
            
m_pBrowser.Create(    m_hWnd, rcDefault, _T("about:blank"),
        WS_HSCROLL| WS_VSCROLL| WS_CHILD | WS_VISIBLE | 
        WS_CLIPSIBLINGS | WS_CLIPCHILDREN );
m_pBrowser->Navigate(_bstr_t("http://www.codeproject.com"),NULL,
        NULL,NULL,NULL);

        

We can change the _T("about:blank") by the CLSID of the control we want to create "{XXXXX-XXXXX-XXXXX...}".

Closing Words

Well, I expect you will find this article useful and helpful for you, if this is the case and you find anything wrong here, please, send me an email and I will be very happy to solve the mistake and re-upload this article. Bye!

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

Jesus Salas
Chief Technology Officer wave-vs.net
Spain Spain
Member
No Biography provided

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
QuestionProblem with the keyboard responce [modified]memberBlackGad25 Jul '07 - 9:12 
This is a very good sample, but I have problem with it.
 
In the HTML forms, like edits,there are some control buttons and shotcuts not responding (del,tab,ctrl+c,ctrl+v etc.)
 
Would you help me?Confused | :confused:
 

-- modified at 15:56 Wednesday 25th July, 2007
 
thaks for an exelent exemple..
 
Ive just fogot to change this method %)
 
BOOL CWebWin32SampleView::PreTranslateMessage(MSG* pMsg)
{
 
if((pMsg->message < WM_KEYFIRST || pMsg->message > WM_KEYLAST) &&
(pMsg->message < WM_MOUSEFIRST || pMsg->message > WM_MOUSELAST))
return FALSE;
 
// give HTML page a chance to translate this message
// return (BOOL) SendMessage( WM_FORWARDMSG,0,(LPARAM)pMsg);
 
return (BOOL) m_pBrowser.SendMessage( WM_FORWARDMSG,0,(LPARAM)pMsg);
}

GeneralCan't compile with VS 2005memberMagnus Persson1 Nov '06 - 3:43 
I've been looking for a way to host controls from any OCX (MFC or VB made) in a WTL application.
 
So far I've been able to host them and sink events but there is always a bunch of "First chance exceptions" when I Create() the host and it seems to be some problems inside COleControl.
 
Anyway, when I found this little helper class I thought I'd give it a try.
However, I cannot compile it with VS 2005.
 
I just created a dummy dialog application with "ActiveX Control Hosting" enabled and included the "WtlExt.h" file.
VS 2005 will give me the following error:
 
wtlext.h(30) : error C3203: 'CWTLAxControl' : unspecialized class template can't be used as a template argument for template parameter 'T', expected a real type
 
The line "public CWindowImpl" seems to be the problem but why?
GeneralRe: Can't compile with VS 2005 (Solved) [modified]memberJesus Salas6 Nov '06 - 3:28 
Hi,
 
Substitue CWTLAxControl definition with this one on wtlext.h
 
template <class T, class Interface>
class CWTLAxControl : public CComPtr<Interface>,
                                 public CWindowImpl<CWTLAxControl<T,Interface>,CAxWindow>,
                          public CWTLDispEventHelper<T,Interface>
 
this will solve this issue,
 
(CWTLAxControl on wtl 7.5 is a template class so it must be parametrized)
 
Regards Smile | :)
 
jesús
 

 
-- modified at 11:13 Monday 6th November, 2006
GeneralRe: Can't compile with VS 2005 (Solved)memberMagnus Persson6 Nov '06 - 4:28 
Can you please repost the new definition (or add a new wtlext.h for download)?
The above definition you posted lacks a couple of characters.
GeneralRe: Can't compile with VS 2005 (Solved) [modified]memberJesus Salas6 Nov '06 - 5:09 
Ok, i checked "ignore HTML tags" this time
 
template <class T, class Interface>
class CWTLAxControl :     public CComPtr<Interface>,
               public CWindowImpl<CWTLAxControl<T,Interface>,CAxWindow>,
               public CWTLDispEventHelper<T,Interface>
 
Anyway I send to codeproject an email to add a new download for VC8 on this article
 
Jesús Salas Wink | ;)
 

 

-- modified at 14:16 Monday 6th November, 2006
 
Thanks for codeproject people for update so fast this article! Big Grin | :-D
GeneralRe: Can't compile with VS 2005 (Solved)memberPrabhat.Singh20 Nov '07 - 2:12 
Hi
 
I got this error in your project.Pls can you Help me to resolve it.
 
Error 1 error C3867: 'CWebWin32SampleView::OnSubmit': function call missing argument list; use '&CWebWin32SampleView::OnSubmit' to create a pointer to member c:\documents and settings\prabhat.singh\desktop\webwin32samplevc6\webwin32sampleview.h 73

 
Prabhat Singh

GeneralActiveX in dialogsussAnagor20 Apr '05 - 3:46 
If I've placed ActiveX in dialog, for example MS Data Grid, how do I work with it? I have no need to create new window in that case.
Thank you.
GeneralCompile errorsmemberRobert Edward Caldecott17 Jan '05 - 0:30 
I am using WTL 7.5/ATL 7 and am getting the following error when I attempt to use this code:
 
atlcom.h(4015) : error C3861: '_GetSinkMap': identifier not found, even with argument-dependent lookup
 
Any clues?
 

The Rob Blog
GeneralRe: Compile errorsmemberecmel2 Feb '07 - 7:54 
I had the same problem. Solved by including:
 
BEGIN_MSG_MAP( Your class )
END_MSG_MAP()
 
BEGIN_SINK_MAP( Your class )
END_SINK_MAP()
 
Hope helps.

GeneralRe: Compile errorsmemberMember 34721704 Mar '09 - 22:15 
That worked for me. Thanx a lot.

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web04 | 2.6.130523.1 | Last Updated 6 Nov 2006
Article Copyright 2002 by Jesus Salas
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid