COM组件设计与应用(十八)——属性包
作者:杨老师
下载源代码
一、前言
书接上回,本回着落在介绍属性包 IPersistPropertyBag 接口的实现方法和调用方式。属性包,是以“名称 - 值”的方式提供组件持续性的支持,而“名称 - 值”恰恰又适合于用文本方式来表现。下面的片段是在 HTML 中插入 Microsoft MonthView Control ActiveX 控件后的样式:
<object classid="clsid:232E456A-87C3-11D1-8BE3-0000F8754DA1" id="MonthView1">以文本方式保存组件属性,比较直观、容易修改,上面 HTML 示例中的 <param name="属性名" value="值"> 就很清晰。下面开始介绍如何在组件中实现 IPersistPropertyBag 接口。
<param name="_ExtentX" value="9393">
<param name="_ExtentY" value="4974">
<param name="_Version" value="393216">
<param name="ForeColor" value="0">
<param name="MaxSelCount" value="7">
<param name="MonthColumns" value="1">
<param name="CurrentDate" value="38632">
<param name="MaxDate" value="2958465">
<param name="MinDate" value="-53688">
</object>
STDMETHODIMP Cxxx::get_str(BSTR* pVal)没有什么复杂的,就是实现 str、integer 两个属性值的设置和读取功能。
{
*pVal = m_str.Copy();
return S_OK;
}
STDMETHODIMP Cxxx::put_str(BSTR newVal)
{
m_str = newVal;
return S_OK;
}
STDMETHODIMP Cxxx::get_integer(LONG* pVal)
{
*pVal = m_integer;
return S_OK;
}
STDMETHODIMP Cxxx::put_integer(LONG newVal)
{
m_integer = newVal;
return S_OK;
}
class ATL_NO_VTABLE Cxxx :我们只要手工添加以上内容,而不用自己写任何 IPersistPropertyBag 接口的函数,多简单呀!天空出彩霞呀,地上开红花呀......会唱这只歌的同学请举手,每个人奖励 vckbase 的专家分 500 !
public CComObjectRootEx<...>,
public CComCoClass<...>,
public IDispatchImpl<...>,
public IPersistPropertyBagImpl<Cxxx> // 手工添加派生类
{
... ... ...
BEGIN_COM_MAP(Cxxx)
... ... ...
COM_INTERFACE_ENTRY(IPersistPropertyBag) // 手工添加接口表
END_COM_MAP()
... ... ...
// 手工添加属性映射表,这是 IPersistXXXImpl 所必须的。
// 将来你在写 ActiveX 的时候,ATL 向导会帮我们添加属性映射表
BEGIN_PROP_MAP(Cxxx)
// 参数:"属性名称", 接口属性序号(见IDL文件), 属性页对话窗
PROP_ENTRY("str", 1, CLSID_NULL)
PROP_ENTRY("integer", 2, CLSID_NULL)
END_PROP_MAP()
... ... ...
public:
... ... ...
// 这个成员变量,是 IPersistXXXImpl 所必须的
bool m_bRequiresSave; // 表示属性数据是否已经改变而需要保存
};
STDMETHODIMP CPropertyBag::QueryInterface(const struct _GUID &iid,void ** ppv)以上是调用者(容器)程序的关键部分,其它的管理和协调部分,读者去阅读示例程序代码。编译注册组件,并运行调用者示例程序,显示如下:
{
*ppv = this;
return S_OK;
}
ULONG __stdcall CPropertyBag::AddRef(void)
{ return 1; } // 做个假的就可以,因为反正这个对象在程序结束前是不会退出的
ULONG __stdcall CPropertyBag::Release(void)
{ return 0; } // 做个假的就可以,因为反正这个对象在程序结束前是不会退出的
STDMETHODIMP CPropertyBag::Read(LPCOLESTR pszPropName,VARIANT *pVar,IErrorLog *pErrorLog)
{
// 根据 pszPropName 指定的属性名称,你要提供该属性的值。
// 而值的数据类型已经在 pVal->vt 中指定了。
if( 如果能提供指定的数据 ) return S_OK;
else return E_FAIL;
}
STDMETHODIMP CPropertyBag::Write(LPCOLESTR pszPropName,VARIANT *pVar)
{
// 根据 psaPropName 指定的属性名称和 pVar 提供的值
// 你保存到文本中去吧。
return S_OK;
}