首先声明 这个代码是我千辛万苦写好的 ,我是个小白 刚毕业的 第一次接触控件和动态库 所有几乎把所有坑都踩了一遍 这篇文章也是给小白写的 还请技术大佬路过的求指教
第一个坑:ocx和dll是有区别的 我对它们的理解就是ocx更为简洁 是面向别的平台调用的 其实JAVA的机制 调用ocx很方便 它也算是一个中介 所有它叫控件 意思就是控制其他的组件吧 (指的是dll)
好,步入正题,其实整体下来是很简单很简单,但是对于第一次调用的新手来说,哪怕是最简单的,也犹如登天。
首先,如果我们想调用ocx需要用的工具包了 Jacob http://www.pc6.com/softview/SoftView_463758.html这是下载地址 或者自己在网上下载也可以,里面有两个重要的东西 一个是jacob.jar一个是jacob+版本号+位数.dll
第二个坑:你的电脑是64位的就复制x64的到jdk的bin目录和jre里面的bin目录(最好是lib下也复制)下,32位的就复制x86
接着把jacob.jar复制到你的项目中 这个随便一个目录下面都可以然后 maven依赖导入我给出来
<dependency>
<groupId>com.jacob</groupId>
<artifactId>jacob</artifactId>
<version>1.19</version>
<scope>system</scope>
<!-- 这里填jar包所在的路径 不报红就是对的 -->
<systemPath>${basedir}/src/main/resources/lib/jacob.jar</systemPath>
</dependency>
版本号记得要换成你的版本号。
对了 这个我听人家说jdk的版本和jacob的版本还要匹配 我的是jdk1.8配jacob1.19 没问题的 接着往下走
控件注册 这里注册方法我就不给了(这不是个坑 还是要给大家一些难度的)可以在网上搜 很简单 或者你的厂家给的bat自动注册文件
第三个坑:这个也是最气人的一个坑,网上的人全都没说这个坑 真沙雕 是我亲自测出来的
将你需要调用的ocx文件放在C/windows/(如果你的电脑是64位就放在 SysWOW64目录下,32位就放在System32目录下),网上的人都是直接说放32位文件夹下 我就想问 你们良心不痛吗?坑了我好长时间
然后根据你的dll位数(因为是你去调ocx 然后ocx去调dll)32位的就把jdk换成32位的,不然会报错,64位写的 jdk换成64位,
好 准备工作已经完成 接下来 上代码
package com.hsh.ocx;
import com.jacob.activeX.ActiveXComponent;
import com.jacob.activeX.ActiveXDispatchEvents;
import com.jacob.com.ComThread;
import com.jacob.com.Dispatch;
import com.jacob.com.DispatchEvents;
import com.jacob.com.InvocationProxy;
import com.jacob.com.Variant;
public class JavaOcx {
public static void main(String[] args) throws InterruptedException {
// 通过ProgID调用OCX控件,组件的ProgID对应注册表中mc2.ocx注册后的ProgID值,这里要说一下网上说话说一半的沙雕 我要是知道progID是啥 我会写不出来?progID就是在注册完控件后,注册表ROOT下面会有生成一个文件夹然后复制文件夹名称
//CLSID如果知道的话 里面就这样填CLSID:{你的CLSID}
//ActiveXComponent com = new ActiveXComponent("组件的ProgID或者CLSID") ;
ActiveXComponent com = new ActiveXComponent("MC2.Mc2Ctrl.1") ;
//通过CLSID调用OCX控件
//ActiveXComponent com = new ActiveXComponent("CLSID:74E58985-15BD-483D-A281-4F6D4BB6387E") ;
Dispatch disp = (Dispatch) com.getObject();
int result= Dispatch.call(disp,你要调用的方法名,方法里面需要的参数);
System.out.println("返回的结果为"+result);
}
}
好了 相信这样调用就很完美了 说一下报错哈 如果是普通的报错 需要去自己百度(还是要锻炼动手能力的),如果出现 "灾难性故障" 这个如果你的ocx控件 厂商不允许修改 那赶快换方法 这个走不通了 如果可以修改 就在控件里面添加个函数 (百度一下就出来了)
JAVA调用dll
这个是写给需要直接调用dll文件的小伙伴的,坑很多 我只能把我踩过的坑填给大家
和ocx一样 把要调用的dll放在C/windows/(如果你的电脑是64位就放在 SysWOW64目录下,32位就放在System32目录下)如果放的不对是会报找不到哦
调用dll不用jacob网上的沙雕标题都标不清,我们用JAVA自带的JNA JNA是JAVA后台调用需要用得 是基于JNI开发的升级版,JNI是在前端页面中用js直接来调 不过这种方法IE8之后就不允许了 不允许前端页面直接调硬件
JNA很简单 话不多说上代码
首先我们需要创建一个接口 这个接口的作用 就是把dll中的方法 映射成接口
public interface HDReadCardzx extends Library {
HDReadCardzx INSTANCE = (HDReadCardzx) Native.loadLibrary("这里是dll文件的名称不需要后缀", 这里是接口的名称 需要.class一下);//加载动态库文件
//动态库中调用的方法 方法名要和dll中的方法名一致 参数也要一致
int ReadCertInfo(String pBmpFile, Pointer pName, Pointer pSex, Pointer pNation, Pointer pBirth, Pointer pAddress, Pointer pCertNo, Pointer pDepartment
, Pointer pEffectData, Pointer pExpire, Pointer pErrMsg
);
}
//这句话要加上是转码用的 不过有的小伙伴加上可能没用 这是个坑 我也是在网上找了好久 把项目的编码改一下 只知道idea在哪找 在后面我会有说明
System.setProperty("jna.encoding", "GBK");
//参数的定义 JAVA和C不同 C中的参数会有输入参数和输出参数 但JAVA中的参数需要对应其类型 并且都需要传进去 目前我只用到了C中char类型 输入参数 JAVA中直接String就可以 输出参数 就需要用到Pointer来给参数分配内存空间 这样才会有值 参数如果是其他 类型的可以百度搜对应类型 原理都一样
String pBmpFile = "D:\\zb.bmp";
Pointer pName = new Memory(10);
Pointer pSex = new Memory(2);
Pointer pNation = new Memory(2);
Pointer pBirth = new Memory(50);
Pointer pAddress = new Memory(80);
Pointer pCertNo = new Memory(50);
Pointer pDepartment = new Memory(50);
Pointer pEffectData = new Memory(50);
Pointer pExpire = new Memory(50);
Pointer pErrMsg = new Memory(50);
//这里接收方法返回的结果 通过上面定义的接口常量调用
int card = HDReadCardzx.INSTANCE.ReadCertInfo(pBmpFile, pName, pSex, pNation, pBirth, pAddress, pCertNo, pDepartment, pEffectData, pExpire, pErrMsg);
Map map = new HashMap();
//下面就是把值取出来 需要new一个String对象 我给放到map里面 因为我下面还需要调用
//因为分配的内存空间有空白的字节 需要用到trim()方法 去空
map.put("pName", new String(pName.getByteArray(0, 10)));
// map.put("pSex", new String(pSex.getByteArray(0, 2)));
// map.put("pNation", new String(pNation.getByteArray(0, 2)));
// map.put("pBirth", new String(pBirth.getByteArray(0, 50)));
map.put("pAddress", new String(pAddress.getByteArray(0, 80)));
map.put("pCertNo", new String(pCertNo.getByteArray(0, 50)));
System.out.println(map);
// map.put("pDepartment", new String(pDepartment.getByteArray(0, 50)));
// map.put("pEffectData", new String(pEffectData.getByteArray(0, 50)));
// map.put("pExpire", new String(pExpire.getByteArray(0, 50)));
// map.put("pErrMsg", new String(pErrMsg.getByteArray(0, 50)));
// System.out.print((char) pName.getByteArray(0, 50)[i]);
return map;
至此放在main方法中可以先测试一下
好 写这篇文章的目的 就是不想让新手被网上的一些沙雕误导 太多的坑都不说 话说一半不说了,整个流程基本都是我自己踩着坑慢慢填好的 当然我可能有些地方遗漏了 大家可以留言 我每天都在 会及时解决的 对了 贴代码不要贴一大串子 那样谁看了都烦 ,贴关键的就好。jacob的作用很多 并不局限于调用ocx 小白可以多研究一下哦