用 Visual Basic 4.0 对 象 封 装 继 承 代 码

摘 要

实 用 意 味 着 不 丢 弃 有 价 值 的 东 西 。 过 去 二 十 年 中 开 发 的 大 部 份 代 码 仍 有 价 值 , 重 写 它 们 将 是 一 笔 巨 额 开 销 。 如 何 解 决 这 个 问 题 呢 ? 是 回 到 我 们 开 始 的 地 方 吗 ? 不 , 那 只 会 使 我 们 裹 足 不 前 。 阻 止 旧 的 语 言 的 任 何 新 的 发 展 吗 ? 考 虑 到 我 们 所 谓 新 的 开 发 实 际 上 是 对 旧 的 系 统 的 增 强 , 这 也 不 太 可 能 。 对 已 存 在 的 代 码 进 行 回 收 利 用 吗 ? 也 许 这 是 个 解 决 方 案 ! 已 经 执 行 了 多 年 的 代 码 可 以 考 虑 再 利 用 。 当 然 , 为 了 成 为 当 前 平 台 上 的 目 标 , 这 些 代 码 必 须 在 微 机 环 境 下 工 作 。 这 是 完 全 可 能 的 , 因 为 已 有 应 用 程 序 的 逻 辑 结 构 和 代 码 本 身 都 可 载 入 到 小 型 机 环 境 中 。

Microsoft Visual Basic 编 程 系 统 4.0 版 提 供 了 许 多 将 继 承 代 码 集 成 到 新 的 应 用 程 序 中 的 方 法 。 它 的 创 建 对 象 功 能 使 开 发 者 可 以 将 继 承 代 码 接 口 的 技 术 细 节 隐 藏 到 一 个 性 质 及 方 式 集 合 中 。

为 什 么 要 使 用 继 承 代 码 和 语 言 ?

本 文 中 所 说 的 继 承 代 码 是 指 用 第 三 代 语 言 如 COBOL 或 FORTRAN 编 写 并 以 一 定 方 式 组 织 结 构 的 典 型 代 码 。 也 就 是 说 , 定 义 继 承 代 码 的 不 仅 是 其 使 用 的 语 言 , 还 包 括 其 组 织 结 构 。 例 如 , 用 C 语 言 编 写 的 串 行 执 行 程 序 通 常 也 可 以 认 为 是 一 个 继 承 应 用 程 序 , 仅 管 大 部 份 继 承 代 码 是 用 COBOL 或 FORTRAN 编 写 的 。 有 几 个 因 素 影 响 到 继 承 代 码 的 继 续 使 用 。 其 中 最 重 要 的 两 点 是 已 有 代 码 的 巨 大 数 量 及 继 承 开 发 者 的 宝 贵 技 术 , 这 是 通 过 多 年 的 开 发 代 码 经 验 才 获 得 的 , 应 该 充 份 利 用 。

几 十 亿 行 代 码

据 报 导 现 已 有 的 COBOL 代 码 多 达 数 十 亿 行 , 且 每 年 还 要 增 加 数 百 万 行 。 大 部 份 大 型 系 统 的 开 发 仍 是 利 用 所 谓 继 承 语 言 。 这 种 现 象 并 非 是 对 当 前 技 术 方 向 的 误 解 造 成 , 而 是 由 于 业 界 的 基 本 现 实 。 世 界 上 许 多 已 有 的 系 统 是 用 这 些 语 言 实 现 的 , 且 大 部 份 开 发 人 员 仍 在 继 续 使 用 它 们 。 即 使 所 有 这 些 系 统 的 开 发 立 刻 停 止 , 维 护 工 作 也 将 延 续 到 下 个 世 纪 。

FORTRAN 在 科 学 和 工 程 领 域 仍 作 为 创 建 技 术 软 件 的 理 想 工 具 而 占 统 治 地 位 。 由 于 这 种 语 言 的 结 构 极 适 于 有 效 计 算 , 尤 其 是 对 精 确 的 向 量 计 算 及 统 计 分 析 , 它 不 可 能 被 忽 略 。 用 FORTRAN 写 的 大 部 份 代 码 能 极 好 地 用 于 模 块 化 开 发 环 境 中 。

越 来 越 多 的 新 的 开 发 工 作 正 用 更 新 的 语 言 来 完 成 , 但 同 时 也 存 在 问 题 。 继 承 代 码 包 含 许 多 描 述 公 司 如 何 操 作 的 业 务 规 则 , 这 些 代 码 可 以 翻 译 成 新 的 语 言 , 但 这 需 要 对 开 发 人 员 的 再 次 培 训 及 相 当 的 重 写 时 间 。 培 训 一 些 继 承 开 发 者 使 用 当 前 最 新 的 技 术 和 语 言 并 非 一 项 简 单 的 任 务 , 尤 其 是 从 COBOL 到 C++ 的 转 变 。 然 而 , 训 练 这 些 人 使 用 Visual Basic 4.0 , 并 继 续 借 用 他 们 在 继 承 代 码 的 开 发 过 程 中 获 得 的 技 能 是 可 能 的 。

要 利 用 这 些 技 能 则 要 求 继 承 代 码 可 以 封 装 到 可 再 利 用 的 模 块 中 , 使 其 能 被 当 前 的 各 种 语 言 访 问 。 然 而 , 这 个 过 程 首 先 要 求 理 解 继 承 代 码 的 功 能 如 何 实 现 。 这 种 理 解 也 许 很 难 达 到 , 因 为 这 些 老 的 系 统 中 很 大 一 部 份 并 不 一 定 能 完 全 被 其 开 发 人 员 理 解 , 他 们 对 代 码 的 了 解 通 常 是 第 三 手 的 。

有 一 些 用 继 承 代 码 写 的 应 用 程 序 , 典 型 的 如 报 表 产 生 程 序 和 实 用 函 数 , 可 以 在 独 立 模 式 下 运 行 。 如 果 有 这 些 应 用 程 序 的 源 代 码 , 那 么 通 常 只 需 小 小 的 修 改 , 它 们 就 可 作 为 再 使 用 的 代 码 。 通 过 修 改 代 码 利 用 的 途 径 , 应 用 程 序 能 变 成 一 个 可 重 置 的 模 块 , 如 果 需 要 , 将 来 它 们 可 用 另 一 种 语 言 重 写 。

即 使 继 承 代 码 不 被 理 解 ( 或 不 存 在 ) , 不 愿 使 用 新 语 言 的 开 发 人 员 仍 可 用 继 承 语 言 来 写 新 的 代 码 。 这 个 功 能 使 那 些 善 于 使 用 继 承 系 统 的 人 的 技 术 得 以 继 续 发 挥 作 用 , 它 将 他 们 的 技 术 同 时 用 于 对 老 系 统 的 维 护 和 新 的 开 发 工 作 中 。 经 过 一 段 时 间 , 这 些 人 会 越 来 越 多 地 学 习 新 的 语 言 并 渐 渐 精 于 新 技 术 。

借 用 开 发 技 能

大 量 合 作 开 发 者 仍 在 用 继 承 代 码 工 作 。 他 们 维 护 并 开 发 增 强 用 COBOL , RPG , BAL 和 FORTRAN 写 的 系 统 。 为 了 完 成 好 他 们 的 工 作 , 他 们 需 要 相 当 多 的 技 巧 和 实 际 经 验 。 这 些 经 验 不 应 在 MIS 工 厂 向 新 技 术 的 快 速 转 变 中 丢 失 。 实 际 上 , 这 些 技 能 可 用 来 增 强 新 创 建 系 统 的 功 能 。 每 个 在 他 或 她 的 技 术 被 认 为 是 过 时 时 离 去 的 职 员 都 是 公 司 损 失 的 一 笔 财 富 , 这 个 损 失 是 很 可 观 的 。 我 们 的 想 法 是 不 改 变 这 些 开 发 者 的 所 作 所 为 , 而 是 改 变 他 们 建 立 系 统 的 方 式 。

例 如 , 即 使 一 个 大 型 的 MIS 工 厂 决 定 从 今 天 起 只 使 用  state-of-the -art  开 发 语 言 , 他 们 仍 需 投 入 相 当 多 的 精 力 维 护 当 前 的 继 承 代 码 。 通 常 由 当 前 的 开 发 人 员 处 理 这 项 任 务 , 这 有 两 个 原 因 : ( 1 ) 停 止 所 有 的 维 护 工 作 是 很 危 险 的 ; ( 2 ) 大 部 份 维 护 人 员 不 愿 将 他 们 的 工 作 仅 限 于 维 护 , 他 们 也 想 参 与 新 系 统 的 开 发 。 利 用 本 文 给 出 的 方 法 , 他 们 可 同 时 作 到 这 两 点 : 他 们 可 与 新 的 开 发 小 组 一 起 工 作 并 发 挥 其 知 识 与 技 能 , 从 而 将 他 们 的 技 术 用 到 新 系 统 的 开 发 中 。

 

传 统 的 与 基 于 元 件 的 应 用 程 序 设 计 的 对 比

traditional  Architecture

有 继 承 代 码 开 发 经 验 的 人 员 需 要 培 训 如 何 以 小 片 为 单 位 创 建 系 统 。 这 种 方 式 与 传 统 的 用 诸 如 COBOL 的 语 言 编 写 代 码 截 然 不 同 。 后 者 的 开 发 人 员 创 建 大 型 的 完 整 系 统 , 它 们 只 有 为 数 极 少 的 可 分 离 部 份 。 这 类 系 统 的 代 码 再 利 用 多 半 取 决 于 开 发 人 员 对 过 去 的 项 目 中 各 独 立 的 代 码 库 的 维 护 工 作 。 不 幸 的 是 , 这 种 方 式 不 太 适 于 个 人 之 间 的 代 码 共 享 。 图 1 说 明 了 利 用 第 三 代 语 言 , 或 3GL 的 传 统 应 用 程 序 设 计 。

图 1.  利 用 3GL 语 言 的 传 统 应 用 程 序 设 计

另 一 方 面 , 多 年 来 这 种 传 统 方 式 与 计 算 机 技 术 结 构 完 全 适 应 。 大 部 份 系 统 都 是 带 有 输 入 输 出 终 端 的 大 型 集 中 处 理 式 机 器 。 所 有 处 理 在 一 个 物 理 设 备 上 完 成 , 且 所 有 存 储 及 外 围 设 备 都 在 同 一 个 物 理 空 间 内 。 图 2 显 示 了 此 类 系 统 的 基 本 配 置 。

 

Mainframe Arhitecture

 

 

图 2.   从 顶 层 看 主 机 体 系 结 构

随 着 计 算 机 技 术 的 发 展 , 硬 件 趋 于 更 小 的 网 络 平 台 。 这 种 趋 势 反 过 来 也 促 使 软 件 系 统 形 成 一 种 客 户 / 服 务 器 模 式 , 其 进 程 被 分 配 到 几 个 不 同 的 平 台 完 成 。 这 种 方 式 使 进 程 之 间 彼 此 互 相 隔 离 , 而 通 过 一 定 接 口 连 接 其 函 数 功 能 。 图 3 显 示 了 一 个 典 型 的 客 户 / 服 务 器 体 系 结 构 。

 

Client Server Architecture

图 3.  一 个 典 型 的 客 户 / 服 务 器 体 系 结 构

这 种 客 户 / 服 务 器 方 式 非 常 有 效 , 因 为 它 使 系 统 各 元 件 的 开 发 可 以 充 份 利 用 其 所 在 的 硬 件 平 台 。 当 然 , 这 种 方 式 要 求 从 传 统 方 式 到 系 统 构 造 的 改 变 。 开 发 者 可 以 将 软 件 看 成 一 个 提 供 各 种 服 务 的 元 件 集 合 , 而 不 是 一 个 大 型 的 整 体 系 统 。

 

Services Based Architecture

 

 

图 4   一 个 基 于 服 务 的 体 系 结 构

Microsoft Solutions Framework 使 软 件 发 展 成 为 一 系 列 能 被 其 他 元 件 访 问 的 服 务 元 件 集 合 。 客 户 / 服 务 器 体 系 结 构 使 系 统 中 离 散 的 函 数 开 发 更 加 简 易 , 它 形 成 了 一 种 非 常 结 构 化 的 开 发 方 式 。 图 4 显 示 了 一 个 作 为 一 组 元 件 开 发 的 系 统 。 这 些 服 务 元 件 是 可 执 行 代 码 而 不 是 源 代 码 , 这 意 味 着 它 们 可 作 为 完 整 的 , 通 过 测 试 并 可 替 代 的 对 象 来 共 享 和 再 利 用 。

Microsoft Solutions Framework 之 后 的 开 发 过 程 被 分 成 一 些 更 小 的 项 目 的 集 合 , 每 个 项 目 创 建 一 个 小 型 的 可 再 利 用 系 统 。 在 早 期 的 开 发 周 期 中 , 这 些 系 统 必 须 作 为 独 立 的 模 块 ( 或 元 件 ) 识 别 和 装 载 。 这 些 项 目 的 目 标 是 创 建 既 可 被 当 前 系 统 也 可 被 其 它 系 统 再 利 用 的 模 块 。 这 种 方 式 实 际 上 能 保 证 高 度 的 再 利 用 率 。

基 于 服 务 的 体 系 结 构 对 服 务 的 分 割 取 决 于 应 用 程 序 。 例 如 , 业 务 服 务 通 常 装 在 服 务 器 上 , 但 也 可 装 在 客 户 机 上 。

为 基 于 服 务 的 体 系 结 构 创 建 应 用 程 序 的 开 发 小 组 通 常 由 两 个 独 立 的 部 份 组 成 : 方 案 设 计 组 和 元 件 设 计 组 。 前 者 将 用 户 和 业 务 需 求 提 炼 成 一 些 独 立 的 概 念 , 并 定 义 代 表 这 些 概 念 的 元 件 。 后 者 将 这 些 元 件 变 成 稳 定 的 可 再 利 用 的 高 质 量 代 码 。 然 后 方 案 设 计 组 将 已 有 的 以 及 新 的 元 件 组 合 成 一 个 应 用 程 序 。

利 用 动 态 链 接 库 的 基 于 元 件 的 设 计 技 术

本 文 叙 述 了 继 承 代 码 如 何 编 译 成 可 直 接 被 Visual Basic 4.0 引 用 并 封 装 进 Visual Basic 4.0 对 象 的 函 数 及 例 程 。 这 些 对 象 保 持 了 原 代 码 的 函 数 功 能 , 同 时 还 具 有 Visual Basic 4.0 创 建 的 代 码 的 典 型 的 安 装 使 用 的 简 易 性 。 结 果 对 下 面 两 个 领 域 的 开 发 者 来 说 都 具 有 优 越 性 : 继 承 代 码 开 发 者 更 易 开 发 , 使 用 Visual Basic 4.0 的 开 发 者 也 更 得 心 应 手 。

整 个 过 程 有 如 下 几 步 。 第 一 步 是 将 继 承 代 码 变 成 动 态 链 接 库 , 或 DLL 。 第 二 步 是 将 DLL 封 装 到 Visual Basic 4.0 OLE 对 象 中 并 在 一 个 基 于 Visual Basic 4.0 的 应 用 程 序 中 测 试 此 DLL 。 第 三 步 是 将 DLL 转 变 成 一 个 独 立 执 行 的 对 象 , 它 将 DLL 的 服 务 提 供 给 任 何 可 使 用 OLE 的 开 发 工 具 。

 

DLL 所 扮 演 的 角 色

一 个 DLL 是 一 系 列 编 译 过 的 代 码 , 它 在 运 行 时 被 链 接 成 可 执 行 代 码 。 而 静 态 链 接 库 在 编 译 时 被 链 接 进 其 他 代 码 中 。 前 者 意 味 者 应 用 程 序 被 分 成 好 几 片 开 发 , 而 后 者 说 明 最 终 产 品 是 一 整 个 可 执 行 文 件 。 一 个 DLL 是 一 种 类 型 的 元 件 。

静 态 链 接 与 动 态 链 接 主 要 有 如 下 两 点 不 同 : 首 先 , 静 态 链 接 在 编 译 - 链 接 阶 段 将 所 有 的 代 码 模 块 存 储 到 .EXE 文 件 中 , 无 需 任 何 其 它 可 执 行 文 件 来 保 证 执 行 例 程 的 完 整 性 。 其 次 , 静 态 链 接 产 生 的 可 执 行 模 块 更 大 且 维 护 代 价 更 高 。

而 使 用 DLL 时 , 程 序 在 编 译 - 链 接 周 期 会 被 告 知 缺 少 哪 些 例 程 以 及 哪 些 DLL 中 包 含 这 些 例 程 。 编 译 器 最 终 产 生 的 可 执 行 程 序 不 包 含 DLL 中 的 代 码 , 而 是 DLL 的 名 字 以 及 指 示 例 程 在 DLL 中 位 置 的 指 针 。

当 程 序 执 行 时 , 装 载 器 在 DLL 中 寻 找 程 序 需 要 的 代 码 例 程 并 将 其 装 入 内 存 以 供 程 序 使 用 。

还 可 以 通 过 修 改 DLL 来 改 变 调 用 主 程 序 的 功 能 而 不 必 替 换 主 程 序 。 此 外 , DLL 可 以 被 好 几 个 应 用 程 序 共 享 。 例 如 一 个 屏 幕 驱 动 器 , 它 的 代 码 可 被 编 译 到 一 个 操 作 环 境 的 每 一 个 可 执 行 程 序 中 , 但 这 很 不 实 用 。 如 果 用 一 个 DLL 来 实 现 , 这 些 代 码 可 以 是 一 个 独 立 的 文 件 , 它 随 显 示 硬 件 的 改 变 而 改 变 或 更 新 。

DLL 还 有 其 他 好 处 。 如 果 某 个 例 程 使 用 大 量 的 安 装 选 项 参 数 , 所 有 这 些 代 码 必 须 在 一 个 静 态 库 中 , 而 利 用 DLL 设 计 的 系 统 只 需 装 入 与 已 选 参 数 有 关 的 代 码 。 在 处 理 象 屏 幕 驱 动 器 这 样 的 代 码 时 这 种 方 式 十 分 有 用 。

说 明 语 句

说 明 语 句 是 Visual Basic 4.0 与 DLL 通 讯 的 桥 梁 。 说 明 语 句 可 用 于 表 格 或 代 码 模 块 的 说 明 部 份 。 通 过 说 明 语 句 , 函 数 或 子 例 程 对 Visual Basic 4.0 来 说 就 象 是 其 语 言 内 部 本 身 的 例 程 一 样 。 下 面 是 一 个 典 型 的 说 明 语 句 :

Declare Sub CREATE Lib "acctstat.dll" _

(ISAMFileStatus As FileStatusType, TargetPath As PathType)

注 意 此 例 程 名 为 CREATE 且 位 于 库 文 件 ACCTSTAT.DLL 中 。 它 使 用 两 个 参 数 : 一 个 用 户 定 义 类 型 称 为 FileStatusType , 另 一 个 用 户 定 义 类 型 称 为 PathType 。 此 例 程 没 有 返 回 值 , 因 此 被 说 明 为 Sub 。

在 这 个 说 明 语 句 之 后 , Visual Basic 4.0 就 可 以 使 用 例 程 CREATE 了 。

任 何 在 客 户 基 础 上 创 建 DLL 的 函 数 都 需 要 一 个 适 当 的 说 明 语 句 。 这 种 语 句 的 创 建 对 有 经 验 的 开 发 者 来 说 并 不 困 难 , 然 而 , 如 果 没 有 对 被 调 用 例 程 的 一 些 底 层 知 识 , 这 却 是 一 项 棘 手 的 任 务 。 ( 本 文 稍 后 叙 述 的 OLE 封 装 过 程 将 帮 助 解 决 此 困 难 。 如 果 需 要 关 于 说 明 语 句 的 更 进 一 步 信 息 , 请 参 阅 Microsoft Visual Basic 4.0 Programmer's Guide 。 )

调 用 DLL

从 Visual Basic 4.0 中 激 活 DLL 很 简 单 , 与 调 用 此 语 言 中 的 任 何 其 它 函 数 或 子 例 程 完 全 一 样 。 例 如 , 下 面 的 代 码 段 即 调 用 了 前 面 的 CREATE 例 程 :

gTargetPath.PathString = gsIsamFileName

Call CREATE(IsamFileStatus, gTargetPath)

MsgBox IsamFileStatus.Message

这 段 代 码 将 要 创 建 的 文 件 名 赋 给 gTargetPath 变 量 ( 它 是 一 个 结 构 ) 的 PathString 域 , 并 调 用 CREATE 子 例 程 。 返 回 信 息 传 递 到 IsamFileStatus 结 构 的 Message 域 中 。 注 意 结 构 的 使 用 并 非 必 须 的 , 而 是 为 了 通 讯 的 方 便 , 此 例 中 是 与 COBOL , 它 使 用 结 构 变 量 的 频 率 很 高 。

上 例 中 对 子 例 程 的 调 用 还 可 通 过 如 下 方 式 实 现 :

CREATE IsamFileStatus, gTargetPath

这 种 替 代 方 式 也 可 完 全 为 Visual Basic 4.0 接 受 , 尽 管 Call 的 使 用 使 代 码 可 读 性 更 强 。

DLL 的 元 件

源 代 码

DLL 中 包 含 的 源 代 码 与 任 何 可 执 行 程 序 大 体 类 似 。 唯 一 的 区 别 是 DLL 没 有 主 程 序 。 它 被 称 为 函 数 或 子 例 程 。

DEF 文 件

为 了 定 义 动 态 链 接 库 中 执 行 的 函 数 和 子 例 程 , 必 须 创 建 一 个 .DEF 文 件 描 述 主 要 的 接 口 。 函 数 名 是 定 义 的 , 但 所 有 参 数 必 须 由 开 发 者 决 定 。 这 就 是 OLE 对 调 用 过 程 的 简 化 之 处 。 类 型 可 在 OLE 内 部 处 理 , DLL 的 内 部 细 节 对 开 发 者 来 说 是 透 明 的 。 请 注 意 许 多 编 译 器 都 有 不 用 .DEF 文 件 创 建 DLL 的 技 术 。 这 通 过 输 出 函 数 的 与 编 译 器 有 关 的 参 数 来 实 现 。

参 数

参 数 说 明 是 DLL 的 定 义 中 最 复 杂 的 过 程 之 一 。 如 果 一 个 参 数 没 有 正 确 说 明 , 系 统 就 有 可 能 产 生 内 存 错 误 并 引 起 应 用 程 序 终 止 运 行 。 仔 细 查 看 继 承 代 码 文 档 以 保 证 对 参 数 大 小 的 正 确 定 义 是 非 常 重 要 的 。

最 易 创 建 一 个 编 译 过 的 DLL 的 语 言 是 C 。 尽 管 C 并 不 是 一 个 真 正 的 继 承 语 言 ( 除 了 对 Visual Basic 4.0 的 最 热 心 的 支 持 者 ) , 它 建 立 了 一 个 良 好 的 基 础 。 如 果 您 使 用 C 的 经 验 丰 富 , 您 便 有 了 理 解 DLL 创 建 及 OLE 封 装 的 基 础 。 C 在 为 Visual Basic 4.0 开 发 高 度 优 化 的 实 用 程 序 上 也 不 失 为 一 种 很 好 的 语 言 。 封 装 优 化 C 代 码 的 一 个 很 好 的 例 子 是 Visual Basic 4.0 Remote Data Object , 它 将 ODBC API 的 复 杂 性 对 用 户 隐 藏 起 从 而 更 易 使 用 。

创 建 一 个 简 单 的 封 装 DLL

要 创 建 一 个 简 单 的 封 装 DLL , 请 激 活 Microsoft Visual C++ 开 发 系 统 2.2 或 更 新 版 本 并 指 定 所 需 的 新 项 目 。 说 明 这 是 一 个 Windows 操 作 系 统 的 DLL 并 指 出 项 目 文 件 将 放 在 哪 里 。 您 开 始 并 不 一 定 要 将 项 目 与 文 件 相 关 联 。 请 注 意 这 是 一 个 32 位 的 编 译 , 因 此 建 立 DLL 外 部 链 接 的 参 数 与 16 位 编 译 不 同 。

然 后 您 就 可 以 打 开 一 个 新 文 件 并 将 其 标 以 .C 后 缀 来 创 建 一 个 源 文 件 。 下 面 一 段 简 单 的 源 文 件 将 输 入 的 整 数 变 成 两 倍 值 。

#include "stdarg.h"

long __stdcall _lDouble(long *lValue)

{

return *lValue + *lValue;

}

函 数 的 返 回 值 是 加 倍 后 的 值 , 初 始 值 不 变 。

编 译 DLL

从 Project 菜 单 中 选 择 Compile 并 保 证 Calling Convention 被 设 置 为 _stdcall 。 这 个 调 用 协 议 与 .DEF 文 件 都 是 为 了 保 证 外 部 名 称 与 例 程 的 内 部 名 一 致 。 C++ 编 译 器 假 定 函 数 名 都 将 在 C++ 程 序 中 用 到 , 因 而 这 些 名 称 被 修 改 成 符 合 相 应 语 法 。

项 目 中 使 用 的 .DEF 文 件 如 下 :

LIBRARY DOUBLE

CODE PRELOAD MOVEABLE DISCARDABLE

DATA PRELOAD MOVEABLE

EXPORTS

 _lDouble @1

在 Visual Basic 4.0 中 运 行 DLL

DLL 通 过 以 下 语 句 链 接 到 基 于 Visual Basic 4.0 的 程 序 中 。 通 常 , 它 在 一 行 内 :

Declare Function lDouble Lib "h:\vboledll\winrel\DOUBLE.DLL" _

Alias "_lDouble" (ByRef lValue As Long) As Long

注 意 您 必 须 确 保 标 志 了 DLL 的 所 在 地 。 如 果 它 位 于 项 目 目 录 下 , 您 必 须 明 确 说 明 此 目 录 在 什 么 地 方 。 如 果 Visual Basic 4.0 缺 省 的 项 目 目 录 即 DLL 所 在 的 目 录 , 您 就 可 以 输 入 DLL 的 名 字 。 Windows 操 作 系 统 先 搜 索 \WINDOWS 目 录 , 然 后 是 \WINDOWS\SYSTEM 目 录 , 如 果 它 在 缺 省 目 录 中 找 不 到 则 搜 索 DLL 的 路 径 。

创 建 一 个 带 文 本 盒 ( 输 入 数 字 “ 1 ” 作 为 文 本 性 质 ) 的 表 格 以 及 一 个 命 令 按 钮 。 在 命 令 按 钮 Click 事 件 中 , 放 置 如 下 代 码 :

Dim lValue As Long   ' Declare a temporary variable.

lValue = Val(Text1.Text)   ' Set the value of the variable.

lValue = lDouble(lValue)   ' Call the DLL.

Text1.Text = Str$(lValue)   ' Rewrite the value in the text box.

运 行 此 代 码 , 注 意 每 按 一 下 按 钮 文 本 盒 中 的 值 则 加 倍 ( 直 到 值 溢 出 ) 。

在 一 个 OLE 服 务 器 中 放 置 DLL

现 在 您 有 了 DLL 函 数 , 您 可 以 将 它 放 到 一 个 OLE 服 务 器 中 , 这 个 过 程 已 被 Visual Basic 4.0 大 大 简 化 。 OLE 服 务 器 的 创 建 大 都 包 括 创 建 类 型 库 及 OLE 服 务 器 信 息 注 册 之 类 的 事 件 。 Visual Basic 4.0 已 为 您 处 理 好 这 些 过 程 , 使 您 能 将 更 多 时 间 花 在 处 理 业 务 事 件 而 不 是 安 装 问 题 上 。

正 如 此 处 所 描 述 的 , 使 用 的 第 一 个 对 象 是 一 个 进 程 外 服 务 器 。 进 程 外 服 务 器 比 进 程 内 服 务 器 具 有 更 多 的 继 承 函 数 功 能 , 因 为 它 能 作 为 一 个 独 立 的 程 序 运 行 。 其 它 进 程 可 以 访 问 它 的 函 数 。 进 程 内 服 务 器 在 应 用 程 序 的 内 存 空 间 中 运 行 , 提 供 更 快 的 数 据 传 送 但 要 牺 牲 一 些 功 能 。 这 些 在 本 文 稍 后 将 作 更 详 细 的 讨 论 。

( 刚 刚 开 发 的 C 例 程 实 现 底 层 功 能 , 能 更 好 地 装 进 进 程 内 服 务 器 的 空 间 , 然 而 , 由 于 这 是 一 个 在 OLE 服 务 器 上 实 现 DLL 的 例 子 , 它 被 简 化 到 每 次 只 执 行 进 程 的 一 步 。 下 一 节 中 将 有 一 个 进 程 内 服 务 器 的 例 子 。 ) 将 DLL 放 到 一 个 对 象 中 是 件 简 单 的 事 情 。 一 个 基 于 Visual Basic 4.0 的 项 目 必 须 用 一 个 类 模 块 创 建 。 此 模 块 中 也 许 有 说 明 语 句 。 对 象 的 名 字 应 能 被 外 部 访 问 , 且 允 许 参 数 传 递 。 )

您 必 须 采 取 如 下 几 步 保 证 其 正 确 工 作 :

1. 将 类 的 性 质 如 下 定 义 :

 

Properties- DoubleClass

 

Instancing 性 质 可 被 设 置 为 单 用 户 或 多 用 户 但 不 能 设 置 NotCreatable 选 项 。 如 果 此 对 象 要 与 外 部 通 讯 则 应 设 置 Public 性 质 , 当 然 , 还 必 须 设 置 Name 性 质 。

Creatable SingleUse 设 置 使 应 用 程 序 每 次 初 始 化 此 对 象 时 都 装 入 服 务 器 的 一 份 新 的 拷 贝 。 Creatable MultiUse 设 置 使 此 对 象 能 被 共 享 , 每 个 对 象 共 享 同 一 份 服 务 。 这 是 一 个 问 题 , 因 为 Visual Basic 4.0 是 一 个 单 线 程 的 系 统 , 也 就 是 说 , 一 个 多 用 户 的 服 务 一 次 只 能 被 一 个 应 用 程 序 使 用 , 在 此 期 间 它 将 阻 塞 所 有 其 它 试 图 使 用 其 功 能 的 用 户 。

2. 在 Tools 菜 单 中 , 单 击 Optiongs , 选 Project 标 签 。 将 Project StartMode 设 为 OLE Server 。

3. 在 您 的 模 块 中 将 Startup Form 设 为 类 似 Main() 的 东 西 。 您 只 有 在 显 示 一 些 信 息 时 才 需 要 一 个 startup form 。

4. 将 Project Name 设 为 DoubleClass 。

5. 设 置 Application Description 使 Object Browser 可 以 查 看 已 有 的 对 象 。

6. 如 下 编 写 Property Let 和 Property Get 例 程 :

Option Explicit

Private glNumber As Long

-----------------------

Property Let lNumber(lInput As Long)

glNumber = lDouble(lInput)  ' Go ahead and double it.

End Property

-----------------------

Property Get lNumber() As Long

lNumber = glNumber

End Property

7. 如 下 编 写 OLE 服 务 器 中 的 Module :

Option Explicit

Declare Function lDouble Lib "h:\vboledll\winrel\DOUBLE.DLL" _

Alias "_lDouble" (ByRef lValue As Long) As Long

----------------

Public Sub main()

End Subsidiary

8. 运 行 OLE 服 务 器 。

9. 运 行 Visual Basic 4.0 的 一 个 单 独 的 实 例 , 其 客 户 代 码 如 下 :

' General declaration section.

Option Explicit

Dim oDoubleObj As Object

' Code in the form.

Private Sub Command1_Click()

oDoubleObj.lNumber = Val(Text1.Text)

Text1.Text = oDoubleObj.lNumber

End Sub

------------------

Private Sub Form_Load()

Set oDoubleObj = CreateObject("doubleOOP.DoubleClass")

End Sub

如 果 您 找 不 到 正 在 测 试 的 Visual Basic 4.0 对 象 的 性 质 , 单 击 工 具 栏 中 的 Object Browser 按 钮 则 可 查 看 可 用 的 性 质 和 方 式 。

10. 检 查 以 保 证 结 果 与 预 期 一 致 。

 

在 OLE 对 象 中 访 问 FORTRAN

现 在 一 个 进 程 外 服 务 器 已 经 创 建 好 了 , 让 我 们 建 立 一 个 与 现 实 更 接 近 一 点 ( 当 然 , 只 是 一 点 点 ) 的 应 用 程 序 : 一 个 利 用 FORTRAN DLL 执 行 计 算 的 统 计 对 象 。 由 于 这 是 一 个 没 有 用 户 接 口 的 实 用 程 序 , 它 将 按 一 个 进 程 内 服 务 器 实 现 。 在 这 里 , 我 们 将 利 用 Microsoft Fortran PowerStation version 4.0 创 建 DLL 代 码 。

创 建 一 个 进 程 内 服 务 器 与 创 建 一 个 进 程 外 外 服 务 器 总 体 说 来 没 有 太 大 区 别 , 除 了 前 者 不 能 创 建 非 模 式 对 话 框 。 因 此 , 进 程 内 服 务 器 对 实 用 函 数 是 很 有 用 的 。

FORTRAN 子 例 程 是 用 FORTRAN 语 言 如 下 说 明 :

SUBROUTINE FSTATS [DLLEXPORT](dSamp, dMean, dSD, dVar, lSize)

也 许 您 会 认 为 由 于 系 统 创 建 了 名 字 FSTATS , 它 也 可 以 被 外 部 进 程 使 用 , 然 而 , 事 实 并 非 总 是 如 此 。

此 项 目 没 有 创 建 .DEF 文 件 , 尽 管 可 以 创 建 一 个 , 因 此 DLL 的 开 发 者 对 实 际 输 出 的 名 字 的 控 制 要 少 一 点 。 这 有 什 么 不 同 吗 ?

对 于 这 个 编 译 器 ( 还 有 Visual C++ 和 其 它 编 译 器 ) , 答 案 是 肯 定 的 。 输 出 函 数 的 名 字 并 非 总 是 与 代 码 中 的 一 致 , 除 非 您 在 .DEF 文 件 中 规 定 这 样 命 名 。 例 程 的 用 户 必 须 知 道 文 件 名 才 可 以 访 问 此 例 程 。 您 在 代 码 中 赋 给 函 数 的 名 字 不 能 保 证 与 输 出 的 一 样 。 另 外 还 要 注 意 在 32 位 的 编 程 环 境 中 所 有 的 函 数 名 都 是 对 大 小 写 敏 感 的 。 这 使 对 它 们 的 访 问 进 一 步 复 杂 化 。

程 序 DUMPBIN.EXE ( 在 Visual C++ 编 译 器 的 BIN 子 目 录 下 ) 能 帮 助 解 决 这 些 问 题 。 使 用 命 令 dumpbin/EXPORTS meansd.dll 可 得 到 输 出 函 数 的 名 字 。 DLL 示 例 程 序 的 输 出 看 上 去 是 这 样 :

Microsoft (R) COFF Binary File Dumper Version 2.60.5135

Copyright (C) Microsoft Corp 1992-1995. All rights reserved.

Dump of file meansd.dll

File Type: DLL

Section contains the following Exports for meansd.dll

0 characteristics

30201B0C time date stamp Wed Aug 02 20:40:44 1995

0.00 version

1 ordinal base

2 number of functions

2 number of names

ordinal hint name

1 0 _FSTATS@20 (00001010)

2 1 _TEST@0 (00001000)

Summary

1000 .data

1000 .idata

1000 .rdata

1000 .reloc

1000 .text

有 两 样 东 西 被 输 出 : FSTATS 程 序 和 一 个 测 试 函 数 , 它 用 来 更 好 地 显 示 这 个 实 用 程 序 。 FSTATS 程 序 被 引 用 为 _FSTATS@20 , 它 说 明 传 递 的 参 数 占 用 20 个 字 节 的 堆 栈 空 间 , 函 数 _TEST@0 不 占 堆 栈 空 间 ( 它 没 有 参 数 ) 。

必 须 修 改 Visual Basic 4.0 的 说 明 语 句 以 处 理 变 化 的 名 字 。 对 FSTATS 来 说 , 处 理 如 下 :

Public Declare Sub FSTATS Lib "h:\vboledll\MEANSD.DLL" _

Alias "_FSTATS@20" _

(ByRef dSamp As Double, _

ByRef dMean As Double, _

ByRef dSD As Double, _

ByRef dVar As Double, _

ByRef lSize As Long)

注 意 通 过 所 有 的 4 字 节 寻 址 ( 传 递 了 5 个 参 数 ) , 子 例 程 的 调 用 占 用 了 20 字 节 的 堆 栈 空 间 。 示 例 数 组 ( dSamp ) 是 作 为 一 个 指 针 传 给 第 一 个 数 组 元 件 的 。

进 程 内 服 务 器 的 处 理 与 进 程 外 服 务 器 稍 微 有 些 不 同 。 一 开 始 , 您 就 必 须 把 它 作 为 一 个 进 程 内 服 务 器 来 测 试 。 这 是 因 为 进 程 内 服 务 器 不 能 象 进 程 外 服 务 器 那 样 在 运 行 示 调 试 。 确 保 Options 对 话 框 的 Advanced Options 标 签 中 选 中 了 Use OLE DLL Restrictions 。 ( 即 使 将 它 作 为 一 个 进 程 外 服 务 器 运 行 您 也 可 以 选 中 它 。 )

激 活 项 目 的 步 骤 与 进 程 外 服 务 器 一 样 。 调 用 例 程 的 代 码 如 下 。 注 意 方 法 是 传 递 参 数 的 。

Option Explicit

Dim Sample As Object

-------------------

Private Sub Command1_Click()

Dim dVars(100) As Double

Dim dSD As Double

Dim dVar As Double

Dim dMean As Double

Dim lNum As Long

dVars(1) = 100#

dVars(2) = 200#

dVars(3) = 300#

dVars(4) = 400

lNum = 4

' Load the sample data.

Sample.LoadData dVars(), lNum

' Recover the statistics.

Text1.Text = Sample.Mean

Text2.Text = Sample.StandardDev

End Sub

--------------------

Private Sub Form_Load()

' Create an instance of the object.

Set Sample = CreateObject("Statinproc.Sample")

End Sub

---------------------

Private Sub Form_Unload(Cancel As Integer)

' Ensure the object is cleaned up.

Set Sample = Nothing

End Sub

对 象 中 的 代 码 如 下 所 示 :

Private dStandardDeviation As Double

Private dMean As Double

Private dVar As Double

------------------------

Property Get Mean() As Double

' Return the value of the mean.

Mean = dMean

End Property

------------------------

Property Get StandardDev() As Double

' Return the value of the standard deviation.

StandardDev = dStandardDeviation

End Property

------------------------

' The method loads the data and calls the statistical function.

Public Sub LoadData(dArray() As Double, lSize As Long)

' Call the calculation function, saving the results

' in the local copies of mean and standard deviation.

Call FSTATS(dArray(1), dMean, dStandardDeviation, dVar, lSize)

End Sub

进 程 内 和 进 程 外 服 务 器

现 在 我 们 看 到 了 两 种 OLE 服 务 器 , 问 题 是 , 它 们 有 什 么 区 别 ? 事 实 上 , 它 们 的 区 别 是 很 本 质 的 。 下 表 显 示 了 大 致 情 况 。

表 1. 进 程 内 和 进 程 外 服 务 器

进 程 内 服 务 器          进 程 外 服 务 器

作 为 DLL 实 现          作 为 .EXE 实 现

进 程 内 通 讯 迅 速         通 讯 较 慢

只 有 模 式 话 对 话 框         没 有 屏 幕 限 制

不 能 远 程 执 行          有 助 于 实 现 远 程 自 动 化

在 每 个 调 用 进 程 的 内 存 空 间 运 行     在 其 自 己 的 内 存 空 间 运 行

一 个 显 著 的 不 同 是 实 例 。 进 程 内 服 务 器 可 在 每 个 调 用 进 程 内 创 建 一 个 实 例 , 从 而 允 许 服 务 器 的 多 重 实 例 而 不 会 引 起 任 何 冲 突 。 另 一 方 面 , 进 程 外 服 务 器 是 作 为 一 个 单 线 程 的 应 用 程 序 运 行 的 。 每 个 调 用 进 程 外 服 务 器 实 例 的 进 程 必 须 共 享 资 源 , 每 次 只 能 有 一 个 进 程 使 用 资 源 。 如 果 进 程 外 服 务 器 被 创 建 为 一 个 单 用 户 对 象 , 这 就 不 是 一 个 问 题 了 , 因 为 每 个 对 象 都 会 创 建 一 个 新 的 实 例 , 而 一 个 多 用 户 对 象 不 会 在 每 次 创 建 时 都 生 成 一 个 新 的 实 例 。 由 于 它 是 按 单 线 程 运 行 的 , 它 不 可 能 同 时 被 两 个 ( 或 更 多 ) 进 程 使 用 。

如 果 实 现 的 方 式 合 理 的 话 , 进 程 内 通 讯 的 速 度 并 不 是 一 个 真 正 的 问 题 。 如 果 使 用 一 个 进 程 外 服 务 器 , 参 数 必 须 以 一 大 组 为 单 位 传 递 , 且 只 使 用 一 个 通 讯 脉 冲 。 这 说 明 进 程 外 服 务 器 能 很 好 地 包 含 屏 幕 和 核 心 程 序 的 辅 助 应 用 程 序 。 进 程 内 服 务 器 能 很 好 地 包 含 实 用 程 序 , 如 在 数 据 库 访 问 层 和 处 理 业 务 规 则 的 特 殊 函 数 中 。

其 它 问 题

上 节 中 叙 述 的 过 程 可 被 任 何 可 以 创 建 DLL 的 语 言 使 用 , 这 使 Visual Basic 4.0 成 为 一 种 组 合 和 简 化 与 许 多 语 言 的 接 口 的 链 接 性 语 言 。 Visual Basic 4.0 甚 至 可 以 在 一 个 OLE 对 象 内 组 合 几 个 DLL 的 函 数 。

其 它 能 包 含 在 Visual Basic 4.0 DLLs 中 的 语 言 有 : COBOL, Pascal 和 汇 编 语 言 。 实 现 技 术 与 本 文 中 描 述 的 实 质 上 一 样 。 如 果 您 想 使 用 其 它 语 言 创 建 一 个 DLL , 建 议 您 仔 细 阅 读 其 文 档 说 明 以 确 保 您 在 编 译 和 链 接 步 骤 中 使 用 了 正 确 的 参 数 。 这 里 使 用 的 例 子 主 要 是 32 位 的 , 因 为 这 种 对 象 最 灵 活 。 它 们 可 以 在 进 程 内 , 进 程 外 使 用 , 还 可 远 程 使 用 。

许 多 厂 商 为 创 建 DLL 制 造 了 32 位 编 译 器 。 当 您 选 择 继 承 编 译 器 时 , 注 意 它 必 须 支 持 DLL 的 创 建 。 将 继 承 编 译 器 产 生 的 DLL 集 成 到 Visual Basic 4.0 中 与 前 里 叙 述 的 没 有 什 么 区 别 。

Visual Basic 4.0 对 象 使 访 问 其 它 语 言 的 代 码 成 了 一 件 普 通 的 事 情 。 直 接 调 用 DLL 非 常 复 杂 , 看 看 Windows API 的 说 明 代 码 , 您 就 可 以 发 现 一 些 很 有 趣 的 语 法 。 而 对 象 的 实 现 和 使 用 却 很 简 单 。 例 如 , 您 可 以 通 过 Object Browser 查 看 哪 些 接 口 可 用 , 从 而 简 化 开 发 , 使 再 利 用 成 为 现 实 。

 

将 代 码 分 发 给 用 户

Visual Basic 4.0 在 它 的 环 境 中 处 理 对 象 的 注 册 。 然 而 , 当 您 在 分 发 对 象 时 , 必 须 在 目 的 系 统 中 为 它 们 注 册 。 Visual Basic 4.0 中 的 Setup Toolkit 和 大 量 其 它 的 市 场 上 可 买 到 的 工 具 都 能 完 成 此 功 能 。 对 象 不 会 自 动 注 册 ( 或 注 销 ) , 因 此 您 必 须 编 写 适 当 的 代 码 处 理 这 个 过 程 。 这 个 任 务 很 简 单 , 且 Visual Basic 4.0 的 文 档 中 有 详 细 的 说 明 。

远 程 对 象

现 在 可 以 创 建 一 个 对 象 了 , 下 一 步 考 虑 这 个 对 象 的 使 用 。 许 多 应 用 程 序 的 设 计 可 能 要 求 OLE 对 象 位 于 本 地 机 器 上 , 但 Visual Basic 4.0 有 一 个 独 特 的 功 能 使 用 户 可 以 从 另 一 台 机 器 上 远 程 运 行 一 个 进 程 外 服 务 器 。 代 码 实 际 上 是 真 正 在 另 一 台 机 器 上 执 行 , 因 而 您 的 进 程 便 可 以 在 等 待 结 果 的 同 时 仍 自 由 地 做 本 地 机 所 需 要 的 一 切 。

这 意 味 这 您 在 Visual Basic 4.0 中 创 建 的 任 何 进 程 外 服 务 器 可 以 在 其 它 机 器 上 从 Visual Basic 4.0 中 调 用 执 行 。 例 如 , 您 可 以 从 另 一 台 机 器 上 调 用 一 个 信 贷 程 序 检 查 一 个 客 户 的 信 贷 情 况 , 同 时 继 续 您 的 定 货 工 作 。 远 程 进 程 可 以 在 结 束 信 贷 检 查 时 发 出 指 示 并 将 结 果 传 给 您 而 不 浪 费 本 地 机 器 的 任 何 CPU 周 期 。 我 们 的 工 具 使 实 际 的 分 配 工 作 变 得 非 常 简 单 。 正 如 本 文 所 描 述 的 , 所 有 的 工 作 集 中 到 对 象 的 创 建 上 。

这 个 功 能 为 应 用 程 序 的 分 配 提 供 了 许 多 选 择 。 例 如 , 一 个 业 务 规 则 可 能 位 于 一 台 单 独 维 护 的 服 务 器 上 以 保 持 信 息 总 是 最 新 的 。 通 过 Remote Automation , 包 含 业 务 规 则 的 最 新 模 块 的 分 配 变 成 了 简 单 的 更 换 服 务 器 上 的 对 象 , 而 不 是 给 每 个 用 户 发 送 一 份 代 码 的 新 拷 贝 。 结 果 , 维 护 和 管 理 的 费 用 大 大 降 低 。

在 继 承 代 码 中 , OLE 对 象 和 相 应 DLL 都 可 以 位 于 远 程 机 器 上 。 当 系 统 的 代 码 逻 辑 上 发 生 变 化 时 , 系 统 的 每 个 用 户 也 跟 随 变 化 , 这 就 形 成 了 整 个 系 统 的 几 乎 同 步 更 新 。

在 Visual Basic 4.0 Enterprise Edition 中 包 含 能 使 您 将 服 务 器 放 到 其 它 机 器 上 的 工 具 。

注 意 : OLE 服 务 器 的 主 机 必 须 运 行 Windows NT version 3.51 或 Windows 95 。

实 际 上 , 这 些 工 具 设 置 了 每 台 机 器 的 注 册 , 使 OLE 例 程 误 以 为 进 程 是 在 本 地 。 从 Visual Basic 4.0 的 角 度 看 , 这 没 有 什 么 不 同 ; 从 系 统 的 角 度 看 , 差 别 很 显 著 ; 而 从 开 发 者 的 角 度 看 , 所 要 做 的 只 是 运 行 一 个 远 程 管 理 工 具 , 选 择 服 务 器 的 位 置 , 并 运 行 应 用 程 序 。

远 程 服 务 器 的 内 容 不 在 本 文 的 讨 论 范 围 , 但 相 信 创 建 OLE 对 象 的 最 难 的 部 份 我 们 已 经 为 您 在 这 里 做 了 。 剩 下 较 有 趣 的 分 发 服 务 器 的 部 份 只 是 一 些 拷 贝 代 码 到 服 务 器 中 以 及 点 几 下 鼠 标 的 问 题 了 。