实际上,任何编写计算机程序的人都熟悉对象概念。用对象编程的一个主要的好处是一个特别有用的对象,如一个字符格式化程序,能被一个应用程序的很多不同部分利用。如果您把这种哲学用到逻辑结论,就没有理由问为什么不能把应用程序本身看作是对象或被其它应用程序作为对象来使用。这就是设计“组件对象模型”(Component Object Model)或者说 COM 来帮助创建的那种环境。
软件开发者可以使用 COM 的框架来快速、简单地把独立的应用程序改造成大应用程序的工作部分。但一些高级语言,象 Visual Basic 和 Java 语言,不能与 COM 简单建立接口。一个称为 自动控制器的层必需介入 COM 对象和用这些语言写的对象之间。鉴于越来越多的大的应用程序是用 Java 语言写的,需要一种便于集成的工具。Microsoft 所采用的 Java 平台 ― Visual J++,有内置的自动控制器,但是标准 Java 用户没有这个好处。
Bridge2Java 通过在 Java 程序中允许 COM 对象象其它 Java 对象一样使用来解决这个 Windows 问题。在这篇文章里,我将给您一个 Bridge2Java 的高级概述;我同时也提供一个展示如何使用它的示例。如果您愿意了解更多关于 COM 的知识,请查看下面的 参考资料部分。
一个支持 COM 的程序(也称为
COM 服务器)允许其它程序(也称为
COM 客户机)访问自己的方法和属性的过程称为
自动化。每一个支持自动化的 COM 服务器必须公开一个称为
IDispatch 的特殊接口。通过使用
IDispatch 接口和
Invoke() 方法,一个 COM 客户机可以调用 COM 服务器想公开的任何函数。Bridge2Java 通过用
Invoke() 方法来允许 Java 程序和 COM 服务器通信;这个方法也把值返回给 Java 程序。从 Java 程序员的角度来说,Bridge2Java 允许 COM 对象就象其它 Java 对象一样被 Java 代码"看到"。可以从对象调用函数;数据类型全是 Java 的数据类型;甚至连 COM 事件也被捕获并发送到 Java 程序。
Java 世界和 COM 世界的边界被用“Java 本机接口”(Java Native Interface(JNI))桥接起来了。只有两个 JNI 调用是必需的:一个是创建 COM 服务器,另一个是处理
Invoke() 方法。只要发生了一次 Java 函数调用就调用
Invoke() ;它事实上是整个“Java 到 COM”过程的要核。然而,如果连接 Java 和 COM 对象和通过
Invoke() 传送一个从 Java 代码到 COM 的调用一样简单,那么 Bridge2Java 将会是一个非常简单的程序。Bridge2Java 的实际工作是在把 Java 变量转变成 COM 能理解的变量类型来完成的。变量称为
VARIANT 并且是包含所有可能类型和指出存储的数据实际类型值的结构。大多数 Java 变量巧妙映射到
VARIANT ― 例如,一个
int 很容易地映射到
VARIANT 中的
VT_I4 类型。实际的困难是在于将象
SAFEARRAY 和
BYREF 值这样的 COM 类型映射到 Java 的等价类型。
转换变量的过程由一个 Java 代理调用开始,该调用创建并批量装入一个自定义建立的 Java 版的
VARIANT ,称为
Jvariant 。这个
Jvariant 能包含所有的 Java 变量类型,再加上一个域,该域指出包含的数据应该被转换成 COM 端的哪种类型。Bridge2Java 中的
SAFEARRAYS 被以
Jvariant 数组形式从 Java 代码传入。Bridge2Java 然后在 COM 端构建适当类型的数组并用输入数组的值批量装入它。如果此数组(或任何其它值)是
BYTEREF ,那么 Bridge2Java 必须能用更新的值替代传入的值。它通过使用数个来自 COM 端的允许更新 Java 数组元素的 JNI 调用之一做到这一点。
图 1 展示 Bridge2Java 如何把 Java 命令传送到 COM 服务器的纵览。
图 1. Bridge2Java 纵览
使用 Bridge2Java 的第一步是把 COM 服务器的接口、方法和属性转换成 Java 代理对象和方法。这是由代理生成器(包括 Bridge2Java)完成的,并且要求用户为 COM 服务器定位 typelib。(
typelib 仅仅是 COM 服务器程序员提供的便利;它为 COM 服务器提供了所有接口、方法和属性的有序清单。)Bridge2Java 代理生成器遍历 typelib,并为它所发现的每一个
IDispatch 接口生成 Java 对象。这样创建的每一个 Java 对象包含来自自
IDispatch 接口的所有方法和属性。属性将被生成为
get_ 和
set_ 方法,例如
get_Visible() 和
set_Visible(BOOL visible) 。
我们的样本应用程序将展示 Java 开发者如何能使用 Bridge2Java 和 COM 调用 Lotus 1-2-3 功能。清单 1 展示了来自代理生成器的片段。这个示例类是用于我们应用程序指向 Lotus 1-2-3 的
IDispatch 接口。(1-2-3 的 typelib 称为
L123TYP.TLB )。
这个示例中有几个重要的事情值得注意。一个是列在文件上部的
cslid ;这是
IDispatch 接口的唯一标识并是 COM 访问注册表找到 Lotus 1-2-3 位置时使用的值。当 Bridge2Java 启动 1-2-3 时,COM 传回一个指向
IDispatch 接口的指针,它将被随后的
Invoke() 调用所利用来和 COM 服务器通信。
“Java 到 COM”过程的另一个重要部分是创建并初始化包含传入值和类型的
Jvariant 类。
invoke_method() 调用通常创建几个
Jvariant ,用于每一个传入的参数。在只返回一个值的情况下,
Jvariant 就被隐式地创建并且只传回返回值。
Bridge2Java 也使用所有存在于
invoke_method() 调用的十六进制值。这些值称为
dispids 并且它们唯一标识
_Application 接口中的每一个方法。
Invoke() 使用这些值,连同上面提到的
IDispatch 接口指针和任何必需的
VARIANT ,来唯一定位和调用由这个接口提供的所有方法。
列表 1. Application.java
// Dispatch Proxies
package Lot123;
import com.ibm.bridge2java.*;
import java.util.Date;
public class Application extends Dispatch implements COMconstants
{
public static final String clsid = "{29130071-2EED-1069-BF5D-00DD011186B7}";
public Application()
{
super(clsid);
}
public Application(String clsidin)
{
super(clsidin);
}
public Application(int IDispatch)
{
super(IDispatch);
}
public Application(Object theObject)
{
super(theObject);
}
public Application(int canvasHWND, int nullval)
{
super(clsid, canvasHWND);
}
public Application(String clsidin, int canvasHWND, int nullval)
{
super(clsidin, canvasHWND);
}
public String ExtendedName(Object nametype)
{
Jvariant args[] = {new Jvariant(nametype,VT_VARIANT)};
return invoke_method(args, 0x1000300, DISPATCH_METHOD).StringVal();
}
public void Goto()
{
invoke_method_void(null, 0x1000304, DISPATCH_METHOD);
}
.
.
.
public Object get_Run()
{
return invoke_method(null, 0x100ea00, DISPATCH_PROPERTYGET).ObjectVal();
}
public void set_Run(Object value)
{
Jvariant args[] = {new Jvariant(value, VT_VARIANT)};
invoke_method_void(args, 0x100ea00, DISPATCH_PROPERTYPUT);
}
public String get_ProductVersion()
{
return invoke_method(null, 0x14c0211, DISPATCH_PROPERTYGET).StringVal();
}
public void set_ProductVersion(String value)
{
Jvariant args[] = {new Jvariant(value, VT_BSTR)};
invoke_method_void(args, 0x14c0211, DISPATCH_PROPERTYPUT);
}
}
|
生成代理之后,现在用户可以写 Java 应用程序来和 COM 服务器会话了。清单 2 展示了一个小的程序,它将启动 1-2-3,把一行写到一个单元格,复制那一行,等待一秒钟,然后不保存地关闭 1-2-3。这是个简单的示例,但是它说明了构建一个更复杂的程序所必需的每一件事。很多示例包括在 Bridge2Java 包中,和其它的一起,该包展示了如何捕获事件并在 Java 画布中描绘 COM 服务器。
列表 2. Quick123.java
// Description: This is a Bridge2Java Lotus 1-2-3 demo. This demo brings up
// 1-2-3, writes "This is a test" in the first cell,
// copies the first cell to the cell below it, waits 1 second,
// then quits.
//
// Setup: None
//
// Author: Bill Phillips
//
import Lot123.*;
public class Quick123
{
public static void main(java.lang.String[] args) {
Application app;
Ranges ranges;
Document doc;
Range rangeA1, rangeA2;
try
{
// Set up the com environment.
com.ibm.bridge2java.OleEnvironment.Initialize();
// Create a new document (which starts 123).
doc = new Document();
// Get the application object.
app = new Application(doc.get_Parent());
// Make the application visible.
app.set_Visible(new Boolean("true"));
// Open the Range workbook.
doc = new Document(app.NewDocument());
// Get all of the ranges.
ranges = new Ranges(doc.get_Ranges());
// Get cell A1.
rangeA1 = new Range(ranges.Item(new String("A1")) );
// Set the contents of cell A1
rangeA1.set_Contents("This is a test");
// Get cell A2.
rangeA2 = new Range(ranges.Item(new String("A2")) );
// Copy the contents of cell A1 into cell A2
rangeA1.QuickCopy(rangeA2);
// Wait one second
Thread.sleep(1000);
// Quit 123 without saving
app.Quit("false");
} catch (com.ibm.bridge2java.ComException e)
{
System.out.println( "COM Exception:" );
System.out.println( Long.toHexString((e.getHResult())) );
System.out.println( e.getMessage() );
} catch (Exception e)
{
System.out.println("message: " + e.getMessage());
} finally
{
app = null;
com.ibm.bridge2java.OleEnvironment.UnInitialize();
}
}
}
|
COM 提供了一种体系结构,该体系结构允许在真实组件级别使用程序而不用关心它们的版本、写程序所用的语言甚至它们运行的位置。Java 平台提供了一个易于临时用户学习和使用的语言。Bridge2Java 跨越了复杂仍强大的 COM 世界和 Java 语言的简单性之间的鸿沟。
Bridge2Java 当前是 IBM alphaWorks 技术,这意味着可以下载并评估它,与开发小组分享您的想法。您也可以获取许可把它用到您自己的产品中。单击下面 参考资料中关于 alphaWorks 的 Bridge2Java 页的链接。
- 您可以参阅本文在 developerWorks 全球站点上的
英文原文.
- 请参与关于这篇文章的
讨论论坛。
- 您可以下载并评估 IBM alphaWorks 的
Bridge2Java 包。
-
About.com拥有一套关于 COM 和相关技术的资源。
- 获得更多关于 JNI 的信息,请查看关于这个主题的
Sun 站点。
- 请查看如何用 COM 体系结构使用
IBM 的 MQSeries 中间件。
- “
电子商务工具”(2001 年 1 月 的合作者世界)解释了许多不同类型的对象,包括 Java 和 COM 如何能在单独的异构企业系统中共存。
- 您在为运行 OS/390 的大型机编程吗?
获得更多关于在这样的环境中如何使用 JNI 的信息。
- 从
开发人员 Java 技术专区获得更多 Java 技术。
William F. Phillips 为位于纽约的 Endicott 的 IBM 工作,是从事类似 Bridge2Java 和 DirectDOM 这样的项目。请通过 billphil@us.ibm.com 和 William 取得联系。