当前位置: 首页 > news >正文

Mac OS 的Component技术简介

  Component技术主要内容为:Component体、Component Manager(CM)和客户程序(Client)。关于Component技术的完整介绍可参见Apple的官方文档:http://developer.apple.com/documentation/mac/MoreToolbox/MoreToolbox-333.html,它是Inside Macintosh一书的一个章节。

  每个Component相当于一个组件类,而具体的使用必须对Component进行实例化,通过所谓Component Instance实现各种功能。一般而言,CM根据Client要求打开一个Component,就等于创建一个该Component的实例,这也被称创建一个该Component的连接(Connection)。对于这两者都有相应的变量类型予以标识。
  Component的相对应标识是component identifier,句柄名称为Component:
TYPE
  {component identifier}
  Component         = ^ComponentRecord;
  ComponentRecord   = 
  RECORD
    data: ARRAY[0..0] OF LongInt;
  END;

  Component Instance对应标识就是Component Instance,句柄名称为ComponentInstance:
TYPE
  {component instance}
  ComponentInstance = ^ComponentInstanceRecord;
  ComponentInstanceRecord = 
  RECORD
    data: ARRAY[0..0] OF LongInt;
  END;

  上述两者在对Component及其实例的各种操作中要频繁用到。

  对于Component,其描述子(Description)是一个非常重要的结构:
TYPE  ComponentDescription = 
  RECORD
    componentType:       OSType;     {type}
    componentSubType:    OSType;     {subtype}
    componentManufacturer:           {manufacturer}
                         OSType;     
    componentFlags:      LongInt;    {control flags}
    componentFlagsMask:  LongInt;    {mask for control }
                                     { flags}
 END;

  这里采用了Pascal语言是因为Component技术是继承于Mac OS 9这样的早期版本,从而保留了当时的传统。其中componentType和componentSubType是Component的类型和字类型标识,均为4字节变量,可表达一个4字母缩写。componentFlags是自定义的Component标记,前8位为系统定义保留,后24位留给Component创建者定义。componentFlagMask仅用在搜索中,是在对CM中注册的Component的列表进行搜索时的敏感标记指定。一般Client通过指定该结构使用诸如FindNextComponent之类的函数就能找到需要的Component。

  Component体的主框架为一个入口函数,它一般由后面将论述的Component Manager调用。其定义一般是:
FUNCTION %ComponentEntryName%(params: ComponentParameters; storage: Handle): ComponentResult;

  这里的Handle是一个分配给当前Component实例的全局存储空间的句柄。 ComponentParameters是入口函数调用的具体参数。ComponentResult是返回值,一般包含错误信息,几乎所有的和Component相关的函数定义或系统调用都采用这个返回类型。如后面所述,一切Component的功能都在入口函数里的分支调用中完成,所以该参数就指明了这种功能需求,它就是由所谓Request Code达成的,后面还要具体论述。其结构如下:

TYPE ComponentParameters = 
  PACKED RECORD
    flags:      Char;                   {reserved}
    paramSize:  Char;                   {size of parameters}
    what:       Integer;                {request code}
    params:     ARRAY[0..0] OF LongInt; {actual parameters}
  END;

  这里的paramSize指明了params数组单元的个数,params就是具体分支调用Component子程序的参数。在Component的入口函数里,典型的分支就是:

CASE (params.what) OF   
  k%ComponentRequestName1%Select: 
    EntryFuncName := CallComponentFunction(params,
                                           C
omponentRoutine(@%Subroutine1%));
  k%ComponentRequestName2%Select:
    EntryFuncName := CallComponentFunctionWithStorage
                                          (storage, params, 
                                           ComponentRoutine(@%Subroutine2%));

    ...
END;

  可见,在入口函数中根据每个Request,调用不同的子程序,而调用的方法是通过CallComponentFunction或CallComponentFunctionWithStorage(子程序需要全局区的句柄以操作全局变量)。

  对于Client(一般指应用程序),并不能直接调用这些分支子程序,甚至也不能调用入口。但功能的确是依据Request对应实现的。它通过定义这些功能的接口(Interface)完成。显然这种接口是语言相关的。在Mac Component的介绍中提供了一种内嵌汇编的方案,即接口函数的实现是一段短小的汇编或机器代码。忽略代码的具体内容,我们以一个名为OvalDrawer的Component中的一个功能为例来看分支子程序和与之对应的接口的关系:

  分支子程序:
FUNCTION OvalSetup (globals: GlobalsHandle;
                    boundsRect: Rect): ComponentResult;

  接口:
FUNCTION DrawerSetup (myInstance: ComponentInstance;
                      VAR r: Rect): ComponentResult;

  并且我们在看一下在入口函数中的相应Request分支响应的情形:
  kDrawerSetupSelect: 
    OvalDrawer := CallComponentFunctionWithStorage
                                             (storage, params,
                                              ComponentRoutine(@OvalSetup));

  注意其中类型为Rect的参数就是这种功能调用的主参数。对于接口,很显然第一个参数指明了Component实例,它由后面叙述的打开Component操作得到;对于分支子程序,第一个参数就是全局数据区句柄,这和分支调用中使用CallComponnetFunctionWithStorage相吻合。
  其实Component功能调用的一般过程就是:Client调用的接口函数触发CM,CM将接口函数参数结构化到params中传入Component的入口,在其中CallComponentFunction系统调用中params又恢复成分支调用子程序的参数并由子程序实现功能。
  除了如上所述Client能打开Component并调用其功能外,Component也能调用另一个Component的功能。这一般有两种方法:一是和Client一样的方法,这样Component就成为Client;二是通过捕获(Capture)另一个Component或/且设置该Component的一个实例为目标(Targeted),用DelegateComponentCall调用这个被捕获或目标化的Component的功能。此处调用者,通过API函数ComponentSetTarget完成目标化,这会向对方Component发送kComponentSetTarget请求,对方被设置为Targeted,他本身就称为Target(这听上去有些奇怪)或Parent,同时Targeted方也称为Delegate Component。

  (未完待续)

转载于:https://www.cnblogs.com/quanben/archive/2005/05/10/3129031.html

相关文章:

  • Windows运行机理——线程的机制(2)
  • 这两天用web标准写了个首页样式,放出pp
  • OpenSolaris的精神本质
  • ActiveX分类
  • 通过gem安装rails
  • 辞职了……
  • 从sql2000导入数据到sql2005的问题
  • SqlDataAdapter的几种常用方法
  • 推荐好书《JOEL说软件》
  • WorkFlow 实施记录(1)
  • 客户端效果总结
  • Movie
  • C#.Net一百零一夜(第一夜)
  • 华为成功破解磁悬浮列车WCDMA无缝覆盖难题
  • 数据结构-翻牌游戏
  • [LeetCode] Wiggle Sort
  • ECS应用管理最佳实践
  • Electron入门介绍
  • JavaScript函数式编程(一)
  • Java知识点总结(JDBC-连接步骤及CRUD)
  • js中的正则表达式入门
  • mysql中InnoDB引擎中页的概念
  • python大佬养成计划----difflib模块
  • Python语法速览与机器学习开发环境搭建
  • Spark VS Hadoop:两大大数据分析系统深度解读
  • SpringBoot几种定时任务的实现方式
  • supervisor 永不挂掉的进程 安装以及使用
  • Vue 动态创建 component
  • vue2.0一起在懵逼的海洋里越陷越深(四)
  • 给初学者:JavaScript 中数组操作注意点
  • 简单基于spring的redis配置(单机和集群模式)
  • 开源中国专访:Chameleon原理首发,其它跨多端统一框架都是假的?
  • 类orAPI - 收藏集 - 掘金
  • 如何使用 OAuth 2.0 将 LinkedIn 集成入 iOS 应用
  • 深入浅出webpack学习(1)--核心概念
  • 使用 @font-face
  • 微信小程序设置上一页数据
  • 云大使推广中的常见热门问题
  • 格斗健身潮牌24KiCK获近千万Pre-A轮融资,用户留存高达9个月 ...
  • #我与虚拟机的故事#连载20:周志明虚拟机第 3 版:到底值不值得买?
  • (Redis使用系列) SpirngBoot中关于Redis的值的各种方式的存储与取出 三
  • (ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY)讲解
  • (笔试题)分解质因式
  • (十)【Jmeter】线程(Threads(Users))之jp@gc - Stepping Thread Group (deprecated)
  • (一)Java算法:二分查找
  • (原)Matlab的svmtrain和svmclassify
  • (转)菜鸟学数据库(三)——存储过程
  • (转)使用VMware vSphere标准交换机设置网络连接
  • .NET Core 中插件式开发实现
  • .net 使用ajax控件后如何调用前端脚本
  • .NET开源的一个小而快并且功能强大的 Windows 动态桌面软件 - DreamScene2
  • @Bean注解详解
  • [ Linux 长征路第五篇 ] make/Makefile Linux项目自动化创建工具
  • [100天算法】-不同路径 III(day 73)
  • [20171113]修改表结构删除列相关问题4.txt