分享
 
 
 

COM组件设计与应用(十八)——属性包

王朝vc·作者佚名  2006-01-17
窄屏简体版  字體: |||超大  

COM组件设计与应用(十八)——属性包

作者:杨老师

下载源代码

一、前言

书接上回,本回着落在介绍属性包 IPersistPropertyBag

接口的实现方法和调用方式。属性包,是以“名称 - 值”的方式提供组件持续性的支持,而“名称 - 值”恰恰又适合于用文本方式来表现。下面的片段是在

HTML 中插入 Microsoft MonthView Control ActiveX

控件后的样式:<object classid="clsid:232E456A-87C3-11D1-8BE3-0000F8754DA1" id="MonthView1">

<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>以文本方式保存组件属性,比较直观、容易修改,上面 HTML 示例中的 <param

name="属性名" value="值">

就很清晰。下面开始介绍如何在组件中实现 IPersistPropertyBag 接口。

二、组件的实现

(1)vc6.0 开发步骤

1、建立一个工作空间(WorkSpace)。

2、在这个工作空间中,建立 ATL 工程,示例程序工程为 Simple18。

3、增加 ATL 对象类,默认全部选项。示例程序中的 ATL 对象短名称是 Property。

4、增加一些属性。在以前的章回中,我们只介绍了增加接口函数的方法,由于今天是首次增加接口属性,所以稍微细致一些。步骤是,在ClassView卡片中选择接口(IProperty)后,执行鼠标右键菜单"Add

Property..."

5、增加 BSTR 类型的接口属性 str,同样的方式,再增加一个

long 型的接口属性 interger。在示例程序中,这两个属性其实只为演示,并没有实际的意义。

6、接口中的属性,多数情况下会对应对象内部的一个成员变量,因此我们现在要添加成员变量。选择对象类名,执行鼠标右键菜单"Add

Member Variable...."

7、添加两个成员变量,一个是 CComBSTR m_str

对应于接口属性 str;另一个是 long

m_integer 对应于接口属性 integer。

(2)vc.net 开发步骤

1、建立一个空白解决方案。

2、在解决方案中,新增 ATL 项目。示例程序中项目名称叫

Simple18,

注意不要选择“属性化编程”方式。

3、添加 ATL 类。选择 “ATL 的简单对象”。默认全部选项。示例程序中 ATL 类短名称为

Property,类名称为 CMyProperty。(注1)

4、

增加一些属性。在以前的章回中,我们只介绍了增加接口函数的方法,由于今天是首次增加接口属性,所以稍微细致一些。步骤是,在类视图卡片中选择接口(IProperty)后,执行鼠标右键菜单"添加属性..."

5、增加 BSTR 类型的接口属性 str,同样的方式,再增加一个

long 型的接口属性 interger。在示例程序中,这两个属性其实只为演示,并没有实际的意义。

6、接口中的属性,多数情况下会对应对象内部的一个成员变量,因此我们现在要添加成员变量。选择对象类名,执行鼠标右键菜单"添加变量...."

7、添加两个成员变量,一个是

CComBSTR m_str 对应于接口属性 str;另一个是

long m_integer 对应于接口属性

integer。

(3)实现代码

至此,我们组件的框架已经完成,下面该完成函数函数的实现了:STDMETHODIMP Cxxx::get_str(BSTR* pVal)

{

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

}没有什么复杂的,就是实现

str、integer

两个属性值的设置和读取功能。

(4)添加 IPersistPropertyBag 接口

还记得我们在上回书中如何添加

IPersistStreamInit 的吗?添加 IPersistPropertyBag

的方法也一样,但这次我们换一个方式,即我们不从 IPersistPropertyBag

派生,而是从 IPersistPropertyBagImpl<>

派生。在 ATL

中,系统帮我们已经完成了很多接口的默认实现,我们只要从 IxxxImpl<>

派生,然后再添加一些必要的映射和变量,就可以了。这样显然要比自己去实现接口的所有函数要简单许多了。其实,如果你明白了本回

IPersistPropertyBagImpl<> 派生的方法后,你完全可以修改前回书中的实现方法,从

IPersistStreamInit 派生改进为从

IPersistStreamInitImpl<> 派生。class ATL_NO_VTABLE Cxxx :

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;// 表示属性数据是否已经改变而需要保存

};我们只要手工添加以上内容,而不用自己写任何

IPersistPropertyBag 接口的函数,多简单呀!天空出彩霞呀,地上开红花呀......会唱这只歌的同学请举手,每个人奖励

vckbase 的专家分 500 !

三、调用者的实现

我们在阅读 MSDN 关于

IPersistPropertyBag

接口函数的时候,你会发现还需要一个接口 IPropertyBag

与之配合才能实现属性包功能。而 IPropertyBag

则需要我们在调用者(容器)中来实现该接口。它们之间的关系如下:

前面几回书中,我们已经学会了从 IUnknown

派生类,也学会了从 IDispatch

派生类,也学会了从 ICallBack

派生类......同样,这回我们要从

IPropertyBag

派生了。在示例程序中,我们添加了一个类 CPropertyBag::public

IPropertyBag,同时重载了所有的虚函数。

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;

elsereturn E_FAIL;

}

STDMETHODIMP CPropertyBag::Write(LPCOLESTR pszPropName,VARIANT *pVar)

{

// 根据 psaPropName 指定的属性名称和 pVar 提供的值

// 你保存到文本中去吧。

return S_OK;

}以上是调用者(容器)程序的关键部分,其它的管理和协调部分,读者去阅读示例程序代码。编译注册组件,并运行调用者示例程序,显示如下:

在编辑窗口中你可以随便指定

str 和 interger

的值,然后“启动组件”,那么你设定的属性值就会在启动组件的同时,通过 IPersistPropertyBag

接口设置到组件中(还原了持续性的环境)。而后,你就可以在下面的 Property

分组操作中,“设置/读取”组件的属性了。当“关闭组件”的时候,程序通过调用

IPersistPropertyBag 接口函数,又重新取得组件的属性名称和值保存到编辑窗的文本中了。

四、小结

理解了本回属性包接口的功能,你就能体会出 IE 是如何装载 ActiveX

(注2)控件并设置控件的状态了。

注1:在 vc.net 中,由于系统已经有

CProperty 类,所以这里我们改换名称为 CMyProperty。

注2:通过十八回的学习,我们已经了解组件的一些常用接口,为我们学习

ActiveX 的组件编程打下了基础。下回书,我们就开始学习

ActiveX。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有