📄 vcc7.htm
字号:
<html>
<head>
<title>c++系列</title>
<meta content="text/html; charset=gb2312" http-equiv=Content-Type>
</head>
<p align="center"><script src="../../1.js"></script></a>
<body bgcolor="#ffffff" leftmargin="5" topmargin="1" marginheight="5" marginwidth="5">
<div align=center>
<table border=0 cellpadding=0 cellspacing=0 width=680 align="center">
<tbody>
<tr>
<td width=200 height="59">
</tr>
</tbody>
</table>
<table border=1 bordercolordark=#ffffff bordercolorlight=#ffffff cellpadding=0
cellspacing=0 width=685 align="center" height="70">
<tbody>
<tr>
<td bgcolor=#F9D23C height=14>
<div align=center class=H1> <b><font class="a"><b> 创建适用于多种容器的控件</span></b>
</font></b></font></div>
</td>
</tr>
<tr valign=top>
<td class=H1 height=212>
<p align="right"> <font color="#000000" class="a">作
者 : Raymond Cirincione著 <a href="mailto:emailaddress@188.net">阿良</a>译
</font></span></p>
<p> <font color="#000000" class="a"> </font></span> <font color="#000000" class="a">
即使是一个符合OLE标准的控件,在不同的ActiveX容器里其行为也会偶尔不同。不能成功地适应容器之间的差别将严重影响控件在某些容器内的应用,甚至导致控件完全无法在个别容器使用。
</font></span></p>
<p> <font color="#000000" class="a"> 本文讨论使用Visual
C++创建控件时如何适应容器相关的需求,特别是为大范围内使用而开发ActiveX控件时必须执行的策略。例如,如何解决诸如许可、线程、内容检验、键盘事件响应等问题。
</font></span></p>
<p> <font color="#000000" class="a"> 一、关于ActiveX控件
</font></span></p>
<p> <font color="#000000" class="a"> 在具体讨论容器之间的差别前(这种差别使得为多种容器开发ActiveX控件复杂化),有必要回顾一下何谓ActiveX控件以及它的创建过程。
</font></span></p>
<p> <font color="#000000" class="a"> ActiveX控件可以看成是实现了标准OLE接口的COM对象。所有的控件都必须最终定位于某种容器,如Visual
Basic、Visual C++、IE浏览器。容器使用标准的OLE接口和控件协商。例如,容器可以创建、定制、存储控件以便以后使用。容器和ActiveX控件之间的所有交互都通过标准的OLE接口进行,由此,ActiveX控件追随了“黑盒”这一思想。控件的用户除了需要了解它的外部接口外,并不需要知道它的内部工作过程。只要开发工具(容器)以及编程语言理解并使用标准的OLE接口,就可以在多种容器中使用ActiveX控件。当然,这仅仅是理论;在实践中,没有两种容器是相同的,开发者必须把握它们之间的不同之处。
</font></span></p>
<p> <font color="#000000" class="a"> 创建ActiveX控件开始于选择开发工具。可供选择的工具很多,从VB到Delphi到VJ++。本文由VC++为出发点讨论控件创建。使用VC++可以获得更快的执行速度和对创建过程更多的控制,以及最大范围的平台SDK和API支持。VC++提供了MFC
ActiveX控件向导来简化ActiveX控件的创建。这个向导引导您通过创建控件外壳的每一步。向导提出的第一个问题是是否需要许可。 </font></span></p>
<p> <font color="#000000" class="a"> 二、许可控件 </font></span></p>
<p> <font color="#000000" class="a"> 控件操作有两个不同的环境:运行时和设计时。一个需要许可证的控件包含几个接口用于设计时限制某些访问。缺乏适当许可的用户只能在运行环境下使用该控件,而不能在设计环境下使用它。如果打算在企业内部、Internet、本地Intranet上使用控件,一般会避免使用许可证。然而,如果是出售商业产品或打算限制设计时访问控件的能力,就应该利用许可所带来的优点。
</font></span></p>
<p> <font color="#000000" class="a"> 如果选择许可某个控件,控件向导就自动加入了必要的接口并创建可定制的许可文件(LIC)。剩下必须做的工作只是修改主文档(如myprojectCTL.CPP)中几个变量。请修改许可文件的内容使之符合许可证键:
</font></span></p>
<p> <font color="#000000" class="a"> static const
TCHAR BASED_CODE </font></span></p>
<p> <font color="#000000" class="a"> _szLicFileName[]
= _T("control.lic"); </font></span></p>
<p> <font color="#000000" class="a"> static const
WCHAR BASED_CODE </font></span></p>
<p> <font color="#000000" class="a"> _szLicString[]
="My Unique Validation String"; </font></span></p>
<p> <font color="#000000" class="a"> 在许可文件可用之后,开发工具经常在工程内缓冲控件的许可证键。如果许可文件本身不再可用,应用程序就使用缓冲的许可证键验证控件。在桌面环境下这是可行的,但在Internet(和Intranet)环境下并没有内建的机制以通过HTML安全地缓冲这个许可信息。
</font></span></p>
<p> <font color="#000000" class="a"> 有两种方法解决这个问题。第一,可以使用Microsoft的一个叫LPK_Tool.exe的工具,它是Microsoft
Internet Client SDK的一部份。LPK_Tool.exe能够将许可文件转换为可在HTML文档内引用的加密文件。IE能够在实例化一个需要许可证的控件时从LPK文件提取许可信息:
</font></span></p>
<p> <font color="#000000" class="a"> 第二个办法需要定制控件的许可验证例程。例如,它可以询问容器自己正处于设计模式还是运行模式。控件所继承的类(COleControl)包含成员函数AmbientUserMode,此函数在控件处于设计模式时返回TRUE。
</font></span></p>
<p> <font color="#000000" class="a"> 然而,并非所有容器响应此查询(包括IE浏览器)。此时AmbientUserMode总是返回TRUE;换句话说,它总是假定控件是在设计模式下。如果容器错误地响应查询,可以写一个函数强制控件认为自己处于运行模式,这样就可以避免这个限制了:
</font></span></p>
<p> <font color="#000000" class="a"> BOOL CCtrl::OptimisticAmbientUserMode(){
</font></span></p>
<p> <font color="#000000" class="a"> BOOL bUserMode;
</font></span></p>
<p> <font color="#000000" class="a"> if (!GetAmbientProperty(
</font></span></p>
<p> <font color="#000000" class="a"> DISPID_AMBIENT_USERMODE,
</font></span></p>
<p> <font color="#000000" class="a"> VT_BOOL,
&bUserMode)) </font></span></p>
<p> <font color="#000000" class="a"> bUserMode
= TRUE; </font></span></p>
<p> <font color="#000000" class="a"> //如果容器没有回答则假定为运行模式
</font></span></p>
<p> <font color="#000000" class="a"> return bUserMode;}
</font></span></p>
<p> <font color="#000000" class="a"> 三、线程模型和资源共享
</font></span></p>
<p> <font color="#000000" class="a"> Microsoft的两种线程模型,单线程和单元模型,同样使得在多种容器内使用控件复杂化。单线程控件在单一线程内执行所有对象;单元线程控件可在任何时候任何线程内执行一个对象。
</font></span></p>
<p> <font color="#000000" class="a"> 某些情况下可能需要将特定资源全局化以便控件的所有实例访问。例如,如果控件的多个实例执行许多数据库操作,此时需要为所有实例创建单一的、共享的数据库连接,而不是为每个实例单独创建连接(其它的情况还包括只有一个可用资源的情形,例如设备上下文或端口)。
</font></span></p>
<p> <font color="#000000" class="a"> 在单元模型线程环境下共享资源时有一个重大问题需要解决。例如,两个线程能够同时尝试使用同一个资源。这可能导致数据错误或其它非预期的结果。那么,容器如何才能知道控件是单元模型线程安全的?在类工厂(类对象)调用UpdateRegistry期间控件写入数据到注册表。当控件为线程安全时常量
</font></span></p>
<p> <font color="#000000" class="a"> afxRegApartmentThreading通知容器:
</font></span></p>
<p> <font color="#000000" class="a"> BOOL CCtrl::C3CtrlFactory::UpdateRegistry(
</font></span></p>
<p> <font color="#000000" class="a"> BOOL bRegister){
</font></span></p>
<p> <font color="#000000" class="a"> if (bRegister)
</font></span></p>
<p> <font color="#000000" class="a"> return </font></span></p>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -