* JAVA 中 基 于 的 COM 组 件 调 用 研 究 李 瑞 1 李 永 刚 (1. 北 京 工 业 大 学 计 算 机 学 院, 北 京 100022;2. 首 都 师 范 大 学 信 息 工 程 学 院, 北 京 100037) 摘 要 : 本 文 在 研 究 了 COM 组 件 复 用, 自 动 化 和 JNI 技 术 的 基 础 上, 详 细 阐 述 了 技 术 的 原 理, 指 出 了 它 的 优 势, 并 以 JAVA 程 序 中 通 过 类 调 用 COM 组 件 为 例, 着 重 讨 论 了 其 在 windows 平 台 上 的 应 用 关 键 词 : JAVA,COM,JNI,, 自 动 化, 组 件 中 图 分 类 号 :TP391 2 0 引 言 JAVA 语 言 自 面 世 以 来, 因 其 平 台 的 独 立 性 安 全 性 面 向 对 象 及 多 线 程 等 特 征, 得 到 了 广 泛 的 应 用 在 JAVA 中 我 们 经 常 会 用 到 自 己 或 第 三 方 通 过 非 JAVA 语 言 编 写 的 一 些 功 能 强 大 的 外 部 COM 组 件, 这 就 是 软 件 复 用 技 术 而 在 JAVA 程 序 中, 不 能 简 单 地 直 接 与 COM 组 件 建 立 接 口, 这 时 就 需 要 利 用 JAVA 的 本 地 方 法 接 口 (JNI) 来 完 成 但 使 用 JNI 调 用 COM 组 件 的 过 程 十 分 繁 琐, 因 而 通 过 直 接 创 建 COM 对 象 不 失 为 一 个 捷 径 实 际 上 是 一 个 JAVA 与 COM 自 动 化 组 件 之 间 的 桥 梁, 即 JAVA-COM Bridge 1 COM 组 件 COM(Component Object Model) 是 微 软 的 组 件 对 象 模 型 它 的 核 心 思 想 是 软 件 复 用, 它 的 实 质 是 将 使 用 C++ / VB / Delphi 等 语 言 工 具 编 写 的 程 序 模 块, 经 过 单 独 调 试 编 译 后 生 成 一 些 小 的 二 进 制 可 执 行 程 序, 这 些 二 进 制 程 序 就 是 组 件 组 件 可 以 为 各 种 应 用 程 序 操 作 系 统 和 其 它 的 组 件 提 供 服 务 微 软 的 许 多 技 术, 如 :ActiveX,DirectX,OLE 等 都 是 基 于 COM 建 立 的 COM 组 件 有 两 种 [1], 一 是 进 程 内 组 件, 它 是 一 个 DLL ( 链 接 库 ) 文 件 ; 二 是 进 程 外 组 件, 是 一 个 EXE( 可 执 行 程 序 ) 文 件 当 另 外 的 组 件 或 程 序 需 要 调 用 组 件 的 功 能 时, 它 首 先 创 建 一 个 COM 对 象, 然 后 通 过 该 对 象 所 实 现 的 COM 接 口 获 得 组 件 所 提 供 的 服 务 [2] COM 是 面 向 对 象 的 软 件 模 型, 对 象 是 它 的 基 本 要 素 之 一 使 用 COM 对 象 的 应 用 程 序 称 为 客 户 程 序, 而 提 供 COM 接 口 的 库 厂 或 自 动 化 程 序 称 为 服 务 器 程 序 接 口 是 一 组 逻 辑 上 相 关 的 函 数 集 合, 其 中 的 函 数 称 为 接 口 成 员 函 数 COM 接 口 使 应 用 程 序 和 其 它 组 件 可 以 和 COM 组 件 的 功 能 进 行 [3] 通 信 2 自 动 化 技 术 虽 然 COM 规 范 非 常 灵 活, 实 现 COM 对 象 也 确 实 可 以 做 到 语 言 无 关 但 实 际 上 COM 的 母 语 仍 然 是 C ++, 从 COM 接 口 的 定 义 以 及 COM 库 的 API 函 数 就 可 以 发 现, 它 所 使 用 的 一 些 数 据 类 型 在 某 些 弱 类 型 的 高 级 语 言 ( 如 VB 和 VBA) 中 很 难 表 达, 要 想 在 这 些 高 级 语 言 中 实 现 和 使 用 标 准 的 [4] COM 对 象, 有 时 是 非 常 困 难 的, 甚 至 是 不 可 能 的 另 外, 使 用 C++ 编 写 的 程 序 可 以 是 16 位 或 者 32 位 的, 它 的 数 据 结 构 很 灵 活 但 用 JAVA 编 写 的 程 序 只 能 是 32 位 的, 其 数 据 结 构 固 定 因 而 在 JAVA 中 使 用 COM 对 象, 可 能 会 因 为 交 换 参 数 的 数 据 结 构 不 同 而 出 现 错 误 自 动 化 作 为 COM 技 术 的 一 种 特 例 或 者 说 是 一 种 应 用, 为 这 些 高 级 语 言 使 用 组 件 模 块 提 供 了 一 条 有 效 的 途 径 COM 程 序 以 自 动 化 对 象 的 方 式 暴 露 出 内 部 的 数 据 和 功 能, 其 它 应 用 程 序 作 为 它 的 客 户, 通 过 访 问 自 动 化 对 象 的 属 性 和 方 法, 来 达 到 程 序 间 通 信 的 目 的 可 以 说, 自 动 化 是 一 个 管 道, 它 在 需 要 调 用 COM 组 件 的 应 用 程 序 和 COM 组 件 之 间 建 立 了 一 个 规 范 的 桥 梁, 而 自 动 化 程 序 本 身 则 作 为 响 应 应 用 程 序 请 求 的 自 动 化 服 务 器 运 行, 并 实 现 组 件 的 间 接 调 用 和 数 据 交 换 自 动 化 不 是 独 立 于 COM, 而 是 建 立 在 COM 的 基 础 上 的 [5] 一 个 自 动 化 服 务 器 实 际 上 就 是 一 个 实 现 了 IDispatch 接 口 的 COM 组 件, 而 一 个 自 动 化 应 用 程 序 则 是 一 个 通 过 IDispatch 接 口 同 自 动 化 服 务 器 进 行 通 信 的 COM 客 户 程 序 3 JNI 1
JAVA 语 言 被 广 泛 应 用 最 主 要 的 原 因 之 一 就 在 于 它 的 平 台 无 关 性, 而 正 是 由 于 它 跨 平 台 的 特 性, 使 得 它 和 本 地 机 的 各 种 内 部 联 系 变 得 很 少, 约 束 了 它 的 功 能 尤 其 是 在 软 件 复 用 方 面, 无 法 直 接 调 用 COM 对 象, 使 得 JAVA 本 身 的 优 点 大 打 折 扣 解 决 JAVA 对 本 地 操 作 的 一 种 方 法 就 是 JNI JNI( Java Native Interface) 是 一 种 编 程 接 口 JAVA 通 过 它 调 用 本 地 方 法, 而 本 地 方 法 就 是 以 库 文 件 形 式 存 放 的 COM 接 口 ( 在 WINDOWS 平 台 上 是 DLL 文 件 形 式, 在 UNIX 机 器 上 是 SO 文 件 形 式 ) [6] 图 1 给 出 了 JNI 的 工 作 模 式 示 意 图 Application C Side Java Side Functions Exceptions JNI Classes Libraries Libraries 图 1 JNI 工 作 模 式 示 意 图 虽 然 使 用 JNI 解 决 了 JAVA 中 调 用 组 件 方 法 的 有 无 问 题, 但 其 操 作 步 骤 比 较 繁 琐 具 体 如 下 : (1) 编 写 需 要 使 用 到 COM 接 口 的 JAVA 程 序 创 建 一 个 JAVA 类, 装 载 包 含 COM 组 件 的 链 接 库, 并 调 用 本 地 方 法 如 : 类 JniHello. Java 包 含 以 下 部 分 代 码 : static{system.loadlibrary("hello");} // 装 载 COM 链 接 库, 即 组 件 对 应 的 DLL 或 SO 文 件 public native static void HelloWorld(); // 本 地 方 法 调 用, 即 调 用 COM 接 口 函 数 (2) 用 javac JniHello. Java 编 译 它, 会 生 成 JniHello.class (3) 执 行 javah JniHello 命 令, 在 当 前 目 录 下 生 成 JniHello.h 文 件 这 个 头 文 件 就 是 Java 和 C 之 间 的 纽 带 其 中 包 含 了 需 要 调 用 的 本 地 方 法 的 声 明, 随 后 就 要 编 写 C/C++ 程 序 来 具 体 实 现 此 函 数 (4) 本 地 方 法 具 体 实 现 编 写 C/ C++ 源 文 件 JniHello.cpp, 其 中 要 包 含 上 一 步 生 成 的 头 文 件 JNIEXPORT void JNICALL Java_ JniHello_HelloWorld ( JNIEnv * env, jobject obj ){ printf ("Hello world )! \ n" ) ; return ;} (5) 编 译 连 接 成 库 文 件 在 WINDOWS 下 成 生 DLL 文 件 (6) 把 Hello.dll 拷 贝 到 JniHello.class 的 目 录 下, 运 行 JAVA 程 序 这 样, 我 们 就 创 建 了 一 个 自 己 的 COM 组 件 Hello, 并 实 现 了 此 组 件 的 接 口 函 数 在 JAVA 中 的 调 用 当 然, 也 可 以 通 过 在 JniHello.cpp 中 调 用 其 它 WIN32 平 台 上 的 COM 对 象, 间 接 实 现 对 已 有 程 序 的 复 用 其 实, 这 正 是 后 面 要 提 到 的 技 术 所 要 使 用 的 由 此 可 见, 使 用 JNI 技 术 虽 然 可 以 在 JAVA 程 序 中 调 用 本 地 方 法, 但 过 程 复 杂, 使 用 不 便, 并 且 在 参 数 传 递 过 程 中 容 易 出 现 数 据 类 型 不 匹 配 的 错 误 4 2
4.1 的 来 源 是 JAVA 与 COM 组 件 桥 接 的 缩 写 [7], 即 :JAVA-COM Bridge 通 过 使 用 类 库, 我 们 可 以 很 方 便 地 在 JAVA 程 序 中 调 用 COM 自 动 化 组 件 最 初 是 由 美 国 人 Dan Adler 在 Inventure 公 司 担 任 CTO 时 编 写 的 目 的 是 为 了 方 便 众 多 的 程 序 员 在 JAVA2 虚 拟 机 上, 调 用 WIN32 平 台 上 COM 自 动 化 服 务 器 中 的 组 件 当 项 目 以 开 源 的 方 式 在 网 络 上 公 布 以 后, 越 来 越 多 的 人 开 始 参 与 到 项 目 的 研 发 与 改 进 中 去 迄 今 为 止, 的 最 新 版 本 jacob 1.11 已 经 公 布 4.2 的 原 理 的 本 质 还 是 使 用 JNI 技 术 调 用 WINDOS 平 台 下 的 本 地 方 法 对 不 能 通 过 JAVA 程 序 直 接 调 用 的 COM 自 动 化 组 件 ( COM Automation components )Dan Adler 遵 照 JNI 接 口 标 准, 首 先 编 写 了 操 作 COM 自 动 化 组 件 的 JAVA 类, 并 将 与 自 动 化 接 口 有 关 的 函 数 调 用 声 明 成 本 地 方 法 然 后, 使 用 C++ 编 写 了 这 些 本 地 方 法 的 具 体 实 现 在 本 地 方 法 的 C++ 实 现 中, 完 成 了 与 WIN32 平 台 下 的 COM 自 动 化 组 件 的 沟 通 最 后, 将 这 些 C++ 程 序 编 译 连 接 成 jacob.dll 库 文 件 这 样, 在 库 文 件 和 类 包 的 相 互 配 合 下, 一 条 从 JAVA 程 序 到 COM 组 件 的 连 接 道 路 就 完 成 了 当 然, 在 中 还 不 仅 仅 是 形 成 了 桥 接 这 么 简 单 Dan Adler 还 在 其 中 加 入 了 数 据 类 型 转 换 组 件 生 存 期 控 制, 和 线 程 控 制 等 部 分 JAVA 程 序 通 过 调 用 COM 自 动 化 组 件 的 详 细 机 制 如 图 2 所 示 Microsoft 程 序 功 能 模 块 编 译 连 接 Microsoft COM 组 件 自 动 化 封 装 IDispatch 接 口 JAVA 自 动 化 操 作 类 JNI 技 术 本 地 方 法 调 用 DLL 文 件 调 用 编 译 连 接 对 象 类 JAR 包 封 装 对 自 动 化 组 件 操 作 的 C++ 程 序 JAVA 程 序 图 2 调 用 COM 自 动 化 组 件 的 机 制 简 单 来 说, 其 工 作 机 理 就 是 : 的 JAR 包 中 包 含 使 用 JNI 的 类, 使 用 JNI 技 术 的 类 文 件 3
.class 连 接 头 文 件.h, 头 文 件 与 本 地 方 法 实 现 文 件.c /.cpp 相 互 对 应, 在 本 地 方 法 实 现 文 件 中 又 调 用 了 自 动 化 组 件, 而 自 动 化 组 件 又 是 访 问 COM 组 件 的 统 一 接 口 另 外, 除 了 以 外, 微 软 公 司 也 提 供 了 在 JAVA 中 应 用 COM 组 件 进 行 程 序 设 计 的 类 包, 即 Microsoft com.ms classes 但 与 的 不 同 之 处 在 于, 使 用 com.ms 编 写 JAVA 时 只 能 使 用 JVC (Microsoft's compiler) 编 译 程 序, 并 且 程 序 仅 能 运 行 在 JVIEW(Microsoft's VM) 环 境 下 相 比 只 需 要 添 加 jacob.dll 和 jacob.jar 两 个 文 件 就 可 以 任 意 编 辑 和 运 行 的 便 利 程 度 来 说, 是 受 限 了 许 多 4.3 的 缺 陷 (1) 由 于 作 者 在 开 发 之 初 瞄 准 的 应 用 目 标 就 是 WIN32 平 台 下 的 COM 组 件, 因 而 使 用 的 JAVA 程 序 仅 限 于 WINDOWS 平 台 (2) 直 到 jacob 1.11 版, 对 于 不 同 版 本 的 WINDOWS 系 统, 才 可 以 全 部 兼 容 (3) 不 支 持 用 户 自 定 义 的 COM 组 件 5 的 使 用 软 件 开 发 中 的 一 个 实 例 笔 者 曾 经 参 与 过 北 京 教 育 招 生 考 试 数 据 资 源 系 统 项 目 的 研 发, 使 用 JAVA 作 为 应 用 层 的 语 言 工 具 其 中, 某 个 功 能 涉 及 到 读 取 并 使 用 VBA 写 成 的 宏 代 码 去 操 作 WORD 文 件, 这 就 需 要 在 JAVA 程 序 中 调 用 基 于 COM 技 术 的 ActiveX 组 件 对 象 现 在 仅 以 此 为 例, 讲 解 类 的 使 用 ( 本 项 目 运 行 平 台 为 WINDOWS 2000 SERVER) 5.1 的 部 署 要 在 JAVA 程 序 中 使 用 类, 需 要 经 过 以 下 几 步 操 作 : (1) 下 载 项 目 包, 如 :jacob 1.11.zip, 具 体 参 见 :www.danadler.com/jacob (2) 将 下 载 的 ZIP 文 件 解 压 缩, 把 其 中 的 jacob.jar 文 件 复 制 到 本 机 JDK 目 录 的 LIB 文 件 夹 下, 并 在 环 境 变 量 中 指 名 路 径 ; 另 外, 还 要 把 其 中 的 jacob.dll 文 件 复 制 到 本 机 WINDOWS 目 录 中 的 SYSTEM32 文 件 夹 下 (3) 在 JAVA 工 程 中 引 入 jacob 的 JAR 包 (4) 在 JAVA 程 序 中 声 明 引 用 jacob 类, 如 :import com.jacob.com.*; 5.2 程 序 编 写 (1) 使 用 OFFICE 软 件 中 的 VB 编 辑 器 编 写 调 试 VBA 代 码 作 为 宏 ; 或 直 接 使 用 OFFICE 中 的 宏 录 制 功 能, 生 成 VBA 代 码 (2) 将 生 成 的 宏 取 名 为 MyMacro, 保 存 在 Normal.dot 中 (3) 编 写 调 用 宏 的 JAVA 程 序, 如 下 : import com.jacob.com.*; import com.jacob.activex.*; public class WordMacroCtrl { public void callwordmacro(string filepath,string macroname){ ActiveXComponent wrdcom=new ActiveXComponent("Word.Application"); // 创 建 的 ActiveXComponent 对 象 wrdcom.setproperty("visible", new Variant(true)); // 设 置 对 象 中 的 属 性 Dispatch odocuments = wrdcom.getproperty("documents").todispatch(); // 通 过 对 象, 调 用 自 动 化 接 口, 获 得 COM 组 件 的 函 数 指 针 Dispatch odocument = Dispatch.call(oDocuments, "Open",filePath).toDispatch(); // 打 开 指 定 路 径 下 的 WORD 文 件 Dispatch.call(wrdCom, "Run", new Variant("Normal.NewMacros." + macroname)); // 调 用 存 储 在 Noraml.dot 中 的 宏 代 码, 并 在 打 开 的 WORD 文 件 中 应 用 4
} public static void main(string[] argv){ WordMacroCtrl Ma=new WordMacroCtrl(); Ma.callWordMacro("D:\\MacroTest.doc","MyMacro"); // 调 用 自 定 义 方 法, 传 入 应 用 宏 的 WORD 文 件 路 径 ( 已 经 存 在 的 文 件 ), 以 及 宏 名 称 }} 6 总 结 文 本 的 创 新 点 在 于, 详 细 阐 述 和 分 析 了 COM 组 件 自 动 化 技 术 JNI 以 及 使 用 调 用 自 动 化 组 件 的 原 理 和 关 系, 并 配 合 实 例 加 以 说 明, 突 出 显 示 了 使 用 在 JAVA 程 序 中 调 用 组 件 带 来 的 便 利 应 该 说, 技 术 使 得 在 JAVA 中 调 用 COM 自 动 化 组 件 不 再 是 一 件 繁 琐 的 工 作, 而 真 正 是 独 立 于 平 台 的, 完 全 封 装 的, 数 据 结 构 统 一 的, 简 单 的 类 的 调 用 可 以 相 信, 随 着 软 件 复 用 技 术 的 普 及 和 JAVA 程 序 开 发 的 扩 大 化, 技 术 也 将 不 断 解 决 自 身 问 题, 继 续 向 前 进 步 参 考 文 献 1 冯 正 全.COM 原 理 概 述 [ J ]. 成 都 信 息 工 程 学 院 学 报,2004,19(3):398 402. 2 张 金 波, 孙 海 翠.COM 技 术 及 其 程 序 设 计 [ J ]. 河 海 大 学 常 州 分 校 学 报,2004,18(2):34 38. 3 崔 晓 松, 蒋 波. 一 种 基 于 COM 技 术 的 BBS 实 现 模 型 [ J ]. 微 计 算 机 信 息,2002,18(1):60 62. 4 吴 丽 贤. 基 于 COM 的 自 动 化 及 其 实 现 的 几 种 方 式 [ J ]. 长 春 师 范 学 院 学 报 ( 自 然 科 学 版 ),2005,18(2): 74 77. 5 唐 国 维, 肖 勇 军.COM 中 自 动 化 对 象 的 方 法 调 用 探 析 [ J ]. 应 用 技 术,2006,11(5):24 27. 6 来 社 安. 在 Java 中 访 问 自 动 化 COM 组 件 [ J ]. 电 脑 知 识 与 技 术,2006,11(2):111 144.. 7 Dan Adler.The Project [ OL ].2000.www.danadler.com / jacob. Study on calling COM automation components base on from Java Li rui 1 Li yonggang 2 (1.College of Computer Science and Technology, Beijing University of Technology, Beijing,100022; 2.College of Information Engineering, Capital Normal University,100037) Abstract This article explained the principle of technology in detail, while studying COM components reuse, automation and JNI technology. Pointed out the advantage of, and give an example for calling COM components through in JAVA, have discussed its application on windows emphatically. Key words: JAVA,COM,JNI,,Automation,components 作 者 简 介 李 瑞 (1979 ), 男, 汉, 北 京 市 人, 北 京 工 业 大 学 计 算 机 学 院 2004 级 研 究 生, 研 究 方 向 : 计 算 机 应 用 技 术 Biography Li rui (1979 ), Male, Han nationality, Beijing, Master degree of Beijing University of Technology, Main research field: computer application. * 北 京 市 科 委 项 目 (Y0105003040191) 资 助 5
联 系 方 式 : 北 京 市 海 淀 区 白 堆 子 甲 23 号 院 5 号 楼 1005 室 Leer_lee_2000@hotmail.com 6