日期:2014-05-20  浏览次数:20945 次

求助:Jacob调用OCX的出现“灾难性故障”
本帖最后由 crazyafei 于 2013-04-17 15:55:08 编辑
最近在做一个企业考勤管理的项目,考勤机厂商提供的接口是用delphi开发两个文件(有接口文档说明):CM_Interface.ocx、KmAPI.dll。
因为整个项目采用java开发,不太想再用delphi再写个小程序来实现功能,所有就在网上查找java调用ocx的方法,就找到了jaboc,按说明按以下步骤配置:

1、jacob-1.17-M2.dll放到System32目录下,jacob.jar添加到工程中,在这时候测试过网上一些操作excel转pdf及操作word的例子,能够正常运行;

2、将CM_Interface.ocx、KmAPI.dll放到System32目录下,并用regsvr32注册到系统,clsid为:CLSID:D2FDB5F6-2C07-45E5-B648-AB055861A466,java代码:
ActiveXComponent com = new ActiveXComponent(clsid);
Dispatch dispatch = com.getObject();
这两句代码运行正常,在调用ocx里面的函数
Dispatch.call(this.dispatch,"SetCommTcpPar",1, new Variant(ip), port,password);
出现异常
Exception in thread "main" com.jacob.com.ComFailException: A COM exception has been encountered:
At Invoke of: SetCommTcpPar
Description: 8000ffff / 灾难性故障

at com.jacob.com.Dispatch.invokev(Native Method)
at com.jacob.com.Dispatch.invokev(Dispatch.java:625)
at com.jacob.com.Dispatch.callN(Dispatch.java:453)
at com.jacob.com.Dispatch.call(Dispatch.java:541)
at comet.FingerMachine.connect(FingerMachine.java:44)
at test.Main.main(Main.java:8)

3、以为是函数调用错误什么的,就用C#写了一小段代码,测试了一下这个OCX的功能接口,能够正常运行。

4、尝试用delphi写了一个小的ocx,通过jacob去调用,能够正常运行

5、看到网上有说在ocx中加一个函数,跳过加载时检查是否允许调用的判断(http://lvqingboy-163-com.iteye.com/blog/769358),就把公司以前用的一个ocx加了函数再用jaboc试了一次,能正常运行。

6、终于解决这个问题了,下面这些是在解决问题后写的,算是记记流水帐吧,等项目结束了后再来整理一下。

7、与厂家联系,安排了开发人员配合解决问题,按上面第5点说的方式,添加COleControl.IsInvokeAllowed (DISPID)函数,跳过允许调用的检查,接口就可以正常调用了;

8、在测试接口的过程中,出现了过jvm 栈溢出的异常信息(忘记截图了),经过检查,在ocx中使用了一个比较大的局部变量,造成jvm栈内存溢出异常,将ocx的内存改为堆内存,就正常了,没有尝试过修改jvm的参数配置,不知道会不会有效果;

9、引用传递,ocx中使用了引用传递参数作为返回值,在java中调用的时候需要按下面这种写法,才能正常返回数据,否则会报参数类型错误的异常
Variant userId = new Variant(new Integer(0), true);
Dispatch.call(dispatch, "GetOneUserID",userId);

10、因为是B/S结构程序(Spring、Struts、Hibernate),将jacob-1.17-M2.dll放到System32目录下是不行的,需要放到Tomcat的bin目录下面才能正常使用。

结论:java来调用ocx本来就算是很偏门的东西,而且确实不是java的长处。即便能成功,对ocx也有颇多要求,而且还牺牲了java跨平台的特性

环境:JDK1.7 Eclipse3.4 系统是win7 32位
jacob 灾难性故障

------解决方案--------------------
正在做相关工作 顶一个