java Jacob调用VB编写的DLL(COM组件)

项目上有调用Visual Basic 6.0编写的DLL文件的需求,在使用JNA调用无果后,在网上找了部分资料,整理如下。

为什么用JNA无法调用?

VB生成的COM组件,虽然是dll后缀,但事实上,它应该叫做activex dll,是一种com组件,与标准dll是两个概念。vb生成的dll,虽然也是dll文件,但是它在生成的时候,屏蔽了输出函数,也就是说,你通过dll查看工具查看dll文件可以调用的方法时,是找不到这些函数的入口的,而标准dll则可以通过这种方式查找到函数入口。(如何让vb生成标准dll文件,实际上已经有成熟方法,只是比较麻烦,具体可以参考http://pydoncy.blog.163.com/blog/static/14380839020111149717308/)

而Java调用dll,根据这种区分,也要使用不同的工具。首先,无论是com组件还是dll文件,它们都是windows下的一种接口规范,对于Java来说,不像C#那样天然可以使用。

Java本身的机制是通过虚拟机运行程序的,这种方式,对于实体机器的利用效率不高。为此,Java的开发工程师发明了Jni。Jni本身是为了实现Java程序与实体机器的链接,通过调用一些本地已编译的其他语言的代码,尤其是c和c++,从而实现提高效率的目的。(也使得代码重用率提高了)

因此,想调用vb的com组件,就必须使用jni。但是jni的调用方法太过于繁琐,而且它首先设计于对c和c++代码的调用,需要对调用的函数编写.h的头文件。因此,有其他的一些开源工具,在基于jni的基础上,简化了开发人员的负担,使得开发人员可以通过简单的代码调用,实现目的。

一开始,我们尝试了jawin这个开源工具。jawin对于如何调用dll这种动态链接库,在jni的基础上实现了简单调用的目的。然而,我们一开始就遇到了找不到函数的问题,也就是前文所说的,vb生成的dll文件是屏蔽了函数入口的。当我们发现这种情况后,我们尝试了让vb生成标准dll,然后还是没有达到目的。

之后,通过对vb的进一步了解,我们终于了解到com组件与dll(动态链接库)的区别,然后找到了另一个工具-JACOB。JACOB就是 JAVA-COM Bridge的缩写,提供自动化的访问com的功能,也是通过JNI功能访问windows平台下的com组件或者win32系统库的。jacob对于com组件的访问调用,在方式上已经大大简化,能够像C#一样通过简单的代码调用。
 

看到此文章后,在网上搜了下jacob的用法。并且动起手来。

版本选择

jacob-1.18.jar 对应 JDK1.7*32

 


jar包和环境配置
jacob.jar 放到项目的lib目录
(方案1)
win7
jacob-1.17-x64.dll 放到C:\Windows\System32
jacob-1.17-x86.dll 放到C:\Windows\SysWOW64
(方案2)
把jacob-1.17-x86.dll 放到jdk/jre/bin下,目前选择的这种

判断环境是否配置成功

先使用以下测试代码,判断是否是自己的dll出现问题 

    public static void main(String[] args) {
        ActiveXComponent xl = new ActiveXComponent("Excel.Application");
        Dispatch xlo = (Dispatch)(xl.getObject());
        try {
             System.out.println("version="+xl.getProperty("Version"));
             System.out.println("version="+Dispatch.get(xlo, "Version"));
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            xl.invoke("Quit", new Variant[] {});
        }
    }

未出现问题,下一步编写测试代码

    public static void main(String[] args) {
        //初始化
        ComThread.InitSTA();
        //调用Test.Class1
        ActiveXComponent axc = new ActiveXComponent("Test.Class1");
        //axc.invoke("hello","dll");
        //get MS level dispatch object
        Dispatch myCom = (Dispatch) axc.getObject();
        //调用runme ,返回 hello,world
        Variant result = Dispatch.call(myCom, "runme","world");
        System.out.println(result.getString());
    }

控制台打印hello,world。是不是过程很顺利,哈哈哈要是这么顺利,我会写这个嘛~~~

问题主要出现在new ActiveXComponent对象时参数的传递。在网上找了一些资料,用以下方法解决问题。

报错问题:
1.使用jacob时总是报错“com.jacob.com.ComFailException: Can't get object clsid from progid”

解决方案:
出现这个错误的原因,是因为没有把DLL文件注册到系统注册表。
注册方法: regsvr32 dll文件(绝对路径)

对于dll文件,可以通过这个工具打开查看:eXeScope 下载地址:http://pan.baidu.com/s/1bpsPzWz

打开查看dll文件,关注下CLSID值。然后在windows的注册表中搜这个CLSID。

其实我用eXeScope打开这个dll时并没有看到CLSID值,而是看到了GUID

百般无奈下在注册表中搜索到了这个,ProgID的值就是需要传递的参数

最后需要注意,在VB项目工程中,工程名不能为中文名。不知道是不是乱码原因,调用报错。

 

附:常用操作指令

注册时用 regsvr32     DLL组件名,
卸载时用 regsvr32 /u DLL组件名。            
参考链接:

http://blog.sina.com.cn/s/blog_c0f210170101ctx2.html

https://blog.csdn.net/song_qingwei/article/details/21704429

https://blog.csdn.net/zp357252539/article/details/51586783

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值