在缺少接口的情况下正常降级

由于控件可能不支持 除 IUnknown 以外的任何接口,因此当容器遇到任何特定接口缺失时,必须正常降级。

人们可能会质疑控件的有用性,只不过 是 IUnknown。 但请考虑控件从容器的视觉编程环境接收的优势 (,例如当容器将对象识别为控件时VB) :

  • 对象的按钮显示在工具箱中。
  • 可以通过将对象从工具箱拖到窗体上来创建对象。
  • 用户可以为对象指定在视觉编程环境中识别的名称。
  • 上述 (3) 中的同名可以立即用于为同一窗体上的控件编写任何其他代码, (甚至不同的窗体) 。
  • 容器可以为该对象中可用的任何事件自动提供代码入口点。
  • 容器为任何可用属性提供自己的属性浏览 UI。

当对象无法识别为控件时,它可能会失去所有这些非常强大且有益的集成功能。 例如,在 Visual Basic 4.0 中,很难真正集成一些不是完全意义上的控件的随机对象,但仍可能具有属性和事件。 由于Visual Basic 4 控件的想法非常严格,因此该对象不会获得上述任何集成功能。 但是,即使是使用 IUnknown 的控件,其中控件的生存期决定了某些资源的存在,应该能够获取上述集成功能。

由于当前工具需要大量的控制接口来获得任何优势,因此控件通常会导致过度实现,因此它们包含的代码比实际需要的更多。 可能为 7K 的控件可能最终为 25K,这是 Internet 等领域的一大性能问题。 这也导致人们认为,由于实现所有接口的复杂性,人们只能使用一个工具(如 CDK)实现控件,这会影响这样一个控件所需的大型 DLL(如OC30.DLL)时,增加工作集。 如果不需要所有接口,则这将打开许多开发人员,以编写非常小且轻的控件,并使用直 OLE 或其他工具编写控件,从而最大程度地减少每个控件的开销。

这就是为什么此附录将控件识别为具有 CLSID 和 IUnknown 接口的任何对象。 即使与 IUnknown 无关,具有编程环境的容器也应该能够至少提供功能 #3 和) 注册表项,它也会获得 #1 和 #2。 如果对象为某些事件集提供 IConnectionPointContainer (和 IProvideClassInfo 通常) ,则会获取 #5;如果它支持属性和方法的 IDispatch ,则获得 #6,以及容器中更好的代码集成。

简言之,对象应能够实现与通过 IConnectionPointContainer 公开的 IDispatch 和一个事件集一样少,以获取上述所有视觉特征。

考虑到这一点,下表描述了容器在没有任何可能接口的情况下可能执行的操作。 请注意,仅列出了容器将通过 QueryInterface 直接获取的这些接口。 其他接口(如 IOleInPlaceActiveObject)是通过其他方式获取的。

接口 接口缺失的含义
IViewObject2
控件没有视觉对象,它将自行绘制,因此没有提供明确的范围。 在运行时,当此接口不存在时,容器根本不会尝试绘制任何内容。 在设计时,容器必须至少为此类控件绘制具有名称的某种默认矩形,以便视觉编程环境中的用户可以选择对象并签出其存在的属性、方法和事件。 处理 IViewObject2 的缺失对于良好的视觉编程支持至关重要。
IOleObject
控件不需要站点,也不参与任何嵌入的对象布局协商。 任何信息 (如控件区) 容器可能期望从此接口中填充的默认值。
IOleInPlaceObject
控件不会像标签) 那样就地活动 (,因此从未尝试以这种方式激活。 它的唯一激活可能是其属性页。
IOleControl
控件没有助记音和不使用环境属性,并且不关心容器是否忽略事件。 如果没有此接口,容器就不调用其方法。
IDataObject
该控件不提供任何属性集和任何可缓存的视觉呈现,因此,在没有此接口的情况下,容器会选择缓存某些默认演示文稿, (对CF_METAFILEPICT的支持,特别是) 并禁用任何属性集相关功能。
IDispatch
控件没有自定义属性或方法。 在这种情况下,容器不需要尝试显示任何控件属性,并且应该禁止容器无法识别为属于其自己的扩展控件的任何自定义方法调用, (可能支持方法和属性) 。 由于扩展控件通常将某些 IDispatch 调用委托给控件,因此扩展控件不应期望该控件完全具有 IDispatch
IConnectionPointContainer
控件没有事件,因此容器不必考虑处理任何事件。
IProvideClassInfo
IProvideClassInfo2
控件没有类型信息或事件,或者容器需要通过控件的注册表项进入控件的类型信息。 此接口的存在是一种优化。
ISpecifyPropertyPages
控件没有属性页,因此,如果容器有任何 UI 将调用它们,则容器应禁用该 UI。
IPerPropertyBrowsing
控件本身没有显示名称,没有预先确定的字符串和值,也没有页面映射的属性。 此接口几乎始终用于生成容器用户界面,因此,如果没有此接口,将禁用此类 UI 元素。
IPersist*
控件没有要谈论的持久状态,因此容器不必担心保存任何特定于控件的数据。 当然,容器将以自己的形式或文档保存有关控件的信息,但控件本身对该信息没有任何贡献。
IOleCache
IOleCache2
对象不支持缓存。 容器仍可以通过仅使用 CreateDataCache 创建数据缓存本身来支持缓存。

容器