18.3 访问ActiveX
Java为了保证跨平台,不建议使用ActiveX,因为它会造成和Windows平台的紧密绑定。但也有些特殊应用宁愿失去跨平台特性,也要访问ActiveX。本节就来讨论如何在SWT中访问ActiveX,并给出使用Word控件、Flash控件的两个实例。
18.3.1 在SWT中打开Word文档
如下实例将在窗口容器中打开一个Word文档。
//---------文件名:WordActiveX1.java----------------
shell.setLayout(new FillLayout());
OleFrame oleFrame = new OleFrame(shell, SWT.NONE);//创建ActiveX控件的容器
File file = new File(WordActiveX1.class.getResource("a.doc").toURI());// 创建文档的File对象
OleClientSite clientSite = new OleClientSite(oleFrame, SWT.NONE, file);// 创建一个ole嵌入面板
clientSite.doVerb(OLE.OLEIVERB_SHOW);// 定义类型为显示控件
System.out.println(clientSite.getProgramID());// 打印控件的唯一标识符:“Word.Document.8”
程序说明:
● OleFrame、OleClientSite都Composite的子类。Shell嵌入OleFrame,OleFrame嵌入OleClientSite,三者是一个层层嵌套关系。
● Word文档a.doc和WordActiveX1.java在同一个目录里。
● 这里没有指定用什么控件打开a.doc,则会使用Windows设定的默认打开方式。
因为在Windows中文本文件是默认用记事本打开,所以如果我们要在程序中用Word来打开一个纯文本文件,就需要指定控件。示例如下:
File file = new File(WordActiveX1.class.getResource("a.txt").toURI());
OleClientSite clientSite = new OleClientSite(oleFrame, SWT.NONE, "Word.Document.8", file);
程序说明:Word.Document.8是Word控件在Windows系统中的唯一标识符。这里也可以用Word.Document,这时将自动使用当前版本的Word控件。
18.3.2 在OLE容器里加入菜单
如图18.3所示,这节的实例将给OLE窗口加入几个菜单,使用了三种方式加入菜单,它们所在的位置也各不相同。

图18.3 在OLE窗口里加入菜单
//---------文件名:WordActiveX2.java----------------
shell.setLayout(new FillLayout());
OleFrame oleFrame = new OleFrame(shell, SWT.NONE);
//--------------------- 创建菜单----------------------------------
Menu bar = new Menu(shell, SWT.BAR);
shell.setMenuBar(bar);
// 创建菜单项
MenuItem menu1 = new MenuItem(bar, SWT.CASCADE);
menu1.setText("menu1");
MenuItem menu2 = new MenuItem(bar, SWT.CASCADE);
menu2.setText("menu2");
MenuItem menu3 = new MenuItem(bar, SWT.CASCADE);
menu3.setText("menu3");
// 将菜单项嵌入OLE容器
oleFrame.setFileMenus(new MenuItem[] { menu1 });
oleFrame.setContainerMenus(new MenuItem[] { menu2 });
oleFrame.setWindowMenus(new MenuItem[] { menu3 });
//--------------------- 创建菜单结束----------------------------------
File file = new File(WordActiveX1.class.getResource("a.doc").toURI());
final OleClientSite clientSite = new OleClientSite(oleFrame, SWT.NONE, file);
clientSite.doVerb(OLE.OLEIVERB_SHOW);
System.out.println(clientSite.getProgramID());
//将打开的文件保存为另一个文件。因为用要到clientSite对象,所以把这段语句放在后面
menu1.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
File file = new File("c:\\b.doc");
boolean success = clientSite.save(file, true);
System.out.println(success ? "成功" : "失败");
}
});
18.3.3 调用ActiveX控件的内部方法
每一个控件都有对外公布的方法。通过OleAutomation对象可以调用控件的方法,不过首先要知道控件方法对应的id值。如果是有参数的方法,还要用Variant对象封装方法的参数。控件方法的返回值也封装在Variant对象里,即使是void型方法,其返回的Variant值也不为空,如果为空则表示方法调用失败。下面的示例将调用Word控件的全选方法“void Select()”。
//---------文件名:WordActiveX2.java----------------
menu2.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
OleAutomation automation = new OleAutomation(clientSite);
// 取得全选方法Select对应的id
int[] methodIDs = automation.getIDsOfNames(new String[] { "Select" });
int methodID = methodIDs[0]; //值为65535
System.out.println("methodID = " + methodID);
Variant result = automation.invoke(methodID);
System.out.println(result != null ? "调用成功" : "调用失败");
System.out.println(result);
automation.dispose();
}
});
这里有一个问题,就是怎么知道控件有哪些方法?答案是可以从Windows的注册表里获得这些信息,如果你对注册表非常熟悉的话。另外,还可以用一个专门查看控件信息的小工具oleview.exe,它来自Windows资源工具包“Windows Resource Kit Tools”,你可以从Windows网站上免费下载它,本书的下载网站也提供有下载链接。
安装完后,通过新增到开始菜单的命令行窗口进入安装目录,运行oleview.exe。打开结点“Object Classes → Grouped by Component Category →Embeddable Objects”可以看到Word的控件信息,如图18.4所示。其中控件的唯一标识项在注册表中叫ProgID。

图18.4 oleview的界面 图18.5 IDispatch结点打开的窗口
双击“Microsoft Word文档”下的IDispatch结点,在弹出窗口选择“View TypeInfo…”按钮,可以打开Word控件的方法列表窗口。如图18.5所示,在图框中0x0000ffff(十六进制)是Select方法的id,换成十进制就是65535。
有些方法是有参数的,比如下面这个EditionOptions方法。其中,BSTR是String类型,VARIANT*是int型,optional表示是一个可选参数。
void EditionOptions( [in] WdEditionType Type,
[in] WdEditionOption Option,
[in] BSTR Name,
[in, optional] VARIANT* Format);
18.3.4 使用Flash控件
本小节实例将演示如何使用Flash控件。首先要找到Flash的控件名,象以前不指明控件直接打开word文档的方法,对于Flash行不通了。而且即使是指名控件创建OleClientSite对象时,也不能立即装入Flash文件,否则会出错。实例是通过调用Flash控件提供的装载方法来打开文件。
在Windows注册表中和Flash相关的控件有不少,我们应该用那一个Flash控件呢?借签一下别人的经验和知识吧,通过google搜索C++是如何使用Flash控件的,得知应该使用名为“ShockwaveFlash.ShockwaveFlash”的控件。打开oleview.exe,在结点“Object Classes → Grouped by Component Category →Control”下找到此控件,如图18.6所示。

图18.6 Flash控件
然后再打开图18.6中的IDispatch结点项,从方法列表中找到控件的装载方法:
[id(0x0000008e), helpstring("method LoadMovie")]
void LoadMovie( [in] int layer, //就一个Flash文件,用layer=0就行了
[in] BSTR url); //这个是所装载Flash文件的路径
还有播放方法如下:
[id(0x00000070), helpstring("method Play")]
void Play();
然后完成实例如下:
//---------文件名:FLashActiveX1.java----------------
shell.setLayout(new GridLayout());
OleFrame oleFrame = new OleFrame(shell, SWT.NONE);
oleFrame.setLayoutData(new GridData(GridData.FILL_BOTH));
// OleControlSite是OleClientSite的子类,提供了更多的功能。当然本实例用OleClientSite也一样。
OleControlSite controlSite = new OleControlSite(oleFrame, SWT.NONE, "ShockwaveFlash.ShockwaveFlash");
controlSite.doVerb(OLE.OLEIVERB_SHOW);// 用OleControlSite则需要设置verb类型
// 开始通过OleAutomation来调用控件的方法
final OleAutomation automation = new OleAutomation(controlSite);
int[] methodIDs = automation.getIDsOfNames(new String[] { "LoadMovie" });
// 得到swf文件的绝对路径,然后LoadMovie方法装入swf文件
String file = "file:/" + FLashActiveX1.class.getResource("a.swf").getPath();
Variant[] methodArgs = { new Variant(0), new Variant(file) };// 方法的参数
automation.invoke(methodIDs[0], methodArgs);
Button button = new Button(shell, SWT.NONE);
button.setText("播放");
button.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
// 调用Flash控件的播放方法Play()。这里直接换算出方法的id值112
automation.invoke(112);
}
});






