ATL-固有属性(CStockPropImpl)
2011-07-20 22:53 Clingingboy 阅读(1433) 评论(0) 收藏 举报
继承该类,派生类就可以支持一些固有属性
一实现方法
1.继承CStockPropImpl
class ATL_NO_VTABLE CBullsEye :
    public CStockPropImpl<CBullsEye, IBullsEye, &IID_IBullsEye,
                      &LIBID_ATLINTERNALSLib>,
    ...
2.虽然已经实现,如想对外开发访问属性,必须显示声明
interface IBullsEye : IDispatch {
    const int DISPID_ALTERNATECOLOR = 1;
    const int DISPID_BEEP = 2;
    const int DISPID_CENTERCOLOR = 3;
    const int DISPID_RINGCOUNT = 4;
    const int DISPID_RINGVALUE = 5;
    const int DISPID_APPLICATION = 6;
    const int DISPID_PARENT = 7;
    [propput, bindable, requestedit, id(DISPID_BACKCOLOR)]
    HRESULT BackColor([in]OLE_COLOR clr);
    [propget, bindable, requestedit, id(DISPID_BACKCOLOR)]
    HRESULT BackColor([out,retval]OLE_COLOR* pclr);
    [propput, bindable, requestedit, id(DISPID_BACKSTYLE)]
    HRESULT BackStyle([in]long style);
    [propget, bindable, requestedit, id(DISPID_BACKSTYLE)]
    HRESULT BackStyle([out,retval]long* pstyle);
    [propput, bindable, requestedit, id(DISPID_FORECOLOR)]
    HRESULT ForeColor([in]OLE_COLOR clr);
    [propget, bindable, requestedit, id(DISPID_FORECOLOR)]
    HRESULT ForeColor([out,retval]OLE_COLOR* pclr);
    [propput, bindable, requestedit, id(DISPID_ENABLED)]
    HRESULT Enabled([in]VARIANT_BOOL vbool);
    [propget, bindable, requestedit, id(DISPID_ENABLED)]
    HRESULT Enabled([out,retval]VARIANT_BOOL* pbool);
};
3.当属性发生变更时,可以有一个通知方法
void CBullsEye::OnForeColorChanged( )
{
…
}
void CBullsEye::OnBackColorChanged( )
{
…
}
void CBullsEye::OnBackStyleChanged( )
{
…
}
4.必须为支持的固有属性提供成员变量
public:
    OLE_COLOR                   m_clrBackColor;     // BackColor stock property
    OLE_COLOR                   m_clrForeColor;     // ForeColor stock property
    long                        m_nBorderStyle;     // BorderStyle stock property
    long                        m_nBorderWidth;     // BorderWidth stock property
    long                        m_nBackStyle;       // BackStyle stock property
    BOOL                        m_bEnabled;         // Enabled stock property
变量名可以参考深入解析ATL
二.内部实现
HRESULT STDMETHODCALLTYPE get_Picture(IPictureDisp** ppPicture)
{
    __if_exists(T::m_pPicture) 
    { 
        ATLTRACE(atlTraceControls,2,_T("CStockPropImpl::get_Picture\n"));
        ATLASSERT(ppPicture != NULL);
        if (ppPicture == NULL)
            return E_POINTER;
        T* pT = (T*) this;
        *ppPicture = pT->m_pPicture;
        if (*ppPicture != NULL)
            (*ppPicture)->AddRef();
    }
    return S_OK;
}
CStockPropImpl使用__if_exists来判断子类是否存在这个字段,缺点就是即使变量写错了,编译器也无法判断错误
附__if_exists && __if_not_exists用法
The __if_exists statement tests whether the specified identifier exists. If the identifier exists, the specified statement block is executed.
跟if语句不同,if必须是字段存在的且为1的情况下,__if_exists只是判断字段是否存在而已,并不在意是否为true或者false
// the__if_exists_statement.cpp
// compile with: /EHsc
#include <iostream>
template<typename T>
class X : public T {
public:
   void Dump() {
      std::cout << "In X<T>::Dump()" << std::endl;
      __if_exists(T::Dump) {
         T::Dump();
      }
      __if_not_exists(T::Dump) {
         std::cout << "T::Dump does not exist" << std::endl;
      }
   }   
};
class A {
public:
   void Dump() {
      std::cout << "In A::Dump()" << std::endl;
   }
};
class B {};
bool g_bFlag = true;
class C {
public:
   void f(int);
   void f(double);
};
int main() { 
   X<A> x1;
   X<B> x2;
   x1.Dump();
   x2.Dump();
   __if_exists(::g_bFlag) {
      std::cout << "g_bFlag = " << g_bFlag << std::endl;
   }
   
   __if_exists(C::f) {
      std::cout << "C::f exists" << std::endl;
   }
   return 0;
}
使用宏定义
IMPLEMENT_STOCKPROP(LONG, BackStyle, nBackStyle, DISPID_BACKSTYLE)
IMPLEMENT_STOCKPROP(LONG, BorderStyle, nBorderStyle, DISPID_BORDERSTYLE)
IMPLEMENT_STOCKPROP(LONG, BorderWidth, nBorderWidth, DISPID_BORDERWIDTH)
…
我们可以看下IMPLEMENT_STOCKPROP宏的实现
#define IMPLEMENT_STOCKPROP(type, fname, pname, dispid) \
    HRESULT STDMETHODCALLTYPE put_##fname(type pname) \
    { \
        __if_exists(T::m_##pname) \
        { \
            ATLTRACE(ATL::atlTraceControls,2,_T("CStockPropImpl::put_%s\n"), #fname); \
            T* pT = (T*) this; \
            if (pT->m_nFreezeEvents == 0 && pT->FireOnRequestEdit(dispid) == S_FALSE) \
                return S_FALSE; \
            pT->m_##pname = pname; \
            pT->m_bRequiresSave = TRUE; \
            if (pT->m_nFreezeEvents == 0) \
                pT->FireOnChanged(dispid); \
            __if_exists(T::On##fname##Changed) \
            { \
                pT->On##fname##Changed(); \
            } \
            pT->FireViewChange(); \
            pT->SendOnDataChange(NULL); \
        } \
        return S_OK; \
    } \
    HRESULT STDMETHODCALLTYPE get_##fname(type* p##pname) \
    { \
        __if_exists(T::m_##pname) \
        { \
            ATLTRACE(ATL::atlTraceControls,2,_T("CStockPropImpl::get_%s\n"), #fname); \
            ATLASSERT(p##pname != NULL); \
            if (p##pname == NULL) \
                return E_POINTER; \
            T* pT = (T*) this; \
            *p##pname = pT->m_##pname; \
        } \
        return S_OK; \
    }
其中还会判断是否定义了属性变更事件
三.自定义属性
1.先声明IDL文件
interface IBullsEye : IDispatch {
    const int DISPID_ALTERNATECOLOR = 1;
    const int DISPID_BEEP = 2;
    const int DISPID_CENTERCOLOR = 3;
    const int DISPID_RINGCOUNT = 4;
    const int DISPID_RINGVALUE = 5;
    const int DISPID_APPLICATION = 6;
    const int DISPID_PARENT = 7;
       [propget, bindable, requestedit, id(DISPID_CENTERCOLOR), helpstring("property CenterColor")]
    HRESULT CenterColor([out, retval] OLE_COLOR* pVal);
    [propput, bindable, requestedit, id(DISPID_CENTERCOLOR), helpstring("property CenterColor")]
    HRESULT CenterColor([in] OLE_COLOR newVal);
    };
2.手动实现get,put方法
STDMETHODIMP CBullsEye::get_CenterColor(OLE_COLOR *pVal)
{
    if( pVal == 0 ) return E_POINTER;
    *pVal = m_clrCenterColor;
    return S_OK;
}
STDMETHODIMP CBullsEye::put_CenterColor(OLE_COLOR newVal)
{
    if( m_clrCenterColor == newVal ) return S_OK;
    if(!m_nFreezeEvents)
    {
        if( FireOnRequestEdit(DISPID_CENTERCOLOR) == S_FALSE )
        {
            return S_FALSE;
        }
    }
    m_clrCenterColor = newVal;             // Save new color
    ::DeleteObject(m_centerBrush);         // Clear old brush color
    m_centerBrush = 0;
    m_bRequiresSave = TRUE;                // Set dirty flag
    if( !m_nFreezeEvents )
    {
        FireOnChanged(DISPID_CENTERCOLOR); // Notify container of change
    }
    FireViewChange( );                     // Request redraw
    SendOnDataChange(0);                   // Notify advise sinks of change
    return S_OK;
}
get,put实现几乎与固有属性实现一致,所以也可以直接用宏IMPLEMENT_STOCKPROP在头文件中实现
3.属性与控件呈现
有些属性改变需要重绘UI,那么就需要调用FireViewChange方法
4.关于FireOnChanged、FireOnRequestEdit、FireViewChange等方法的实现
CComControlBase和CComControl提供了这些辅助方法来实现,所以子类还需要继承CComControl
                    
                
                
            
        
浙公网安备 33010602011771号