65.9K
CodeProject 正在变化。 阅读更多。
Home

WTL ActiveX 托管类

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.51/5 (16投票s)

2002 年 8 月 21 日

2分钟阅读

viewsIcon

182317

downloadIcon

1668

用于事件接收器和 ActiveX 托管的 WTL 辅助类

引言

WTL 是我见过的最好的 Win32 编程库,简单而强大。但是有时候我不得不改变主意,使用其他的库和工具,然后我会忘记一些基本的 ATL/WTL 概念,比如:

  • 事件接收器实现
  • ActiveX 实例化
  • 其他基本的,但是难以忘记的概念

因此,我正在用类似 WTL 的方式开发一个小库,它将帮助我(也许也能帮助其他人)更轻松地使用 WTL。

CWTLAxControl

本文中的这个类和其他相关类将帮助你更轻松地使用 ActiveX 控件。

CWTLAxControl 类实现了:

  • 智能指针 (CComPtr<>)。
  • CWindowImpl<> (CAxWindow)。
  • IDispEventImpl<>.

也许它看起来很难使用,但稍等片刻,看看下一个 IExplorer 的实现。使用这个类,你将可以通过 "->" (智能指针) 访问 IWebBrowser2 方法接口,处理窗口消息(宿主窗口),并将来自 ActiveX 宿主的事件传递到你自己的事件处理程序。

        
#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" );
        }
};
        

CWTLAxControl 内部

如果你喜欢上面的实现,那么现在是时候更详细地了解它的工作原理了。

第一步是查看主父类 CWTLAxControl,它看起来像这样:

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;
    };
};
        

当收到 WM_CREATE 消息时,这个类会使用 AttachControl 方法帮助我们将 CComPtr 附加到 ActiveX 控件。此外,这个类派生自 CWindowImpl,这使我们有机会处理所有需要的窗口消息。

最后一个类 CWTLDispEventHelper 将帮助我们设置正确的 IDispEventImpl 实现。

CWTLDispEventHelper 内部

这个类将帮助我们为控件设置事件接收器,它看起来像这样:
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);
      }

};
        
它只有两个方法:EasyAdvise 用于设置事件接收器处理程序,EasyUnadvise 用于取消激活它。

如何创建控件

这是最简单的事情,就像我们在 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("https://codeproject.org.cn"),NULL,
        NULL,NULL,NULL);

        

我们可以将 _T("about:blank") 更改为我们要创建的控件的 CLSID "{XXXXX-XXXXX-XXXXX...}"

结语

我希望你会发现这篇文章对你有所帮助。如果是这样,并且你发现这里有任何错误,请给我发送电子邮件,我将非常乐意解决这个错误并重新上传这篇文章。再见!

© . All rights reserved.