天天看點

JAVA調用OCX和dll執行個體 絕對管用的例子JAVA調用dll

首先聲明 這個代碼是我千辛萬苦寫好的 ,我是個小白 剛畢業的 第一次接觸控件和動态庫 所有幾乎把所有坑都踩了一遍  這篇文章也是給小白寫的 還請技術大佬路過的求指教

第一個坑: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 小白可以多研究一下哦