前述: 公司是做社保,医疗行业的,接了个单子,制作生存认证项目,使用曙光易通的指静脉仪,然后诞生了n多需求,在前期已完成electron的ffi模块来调用dll,现把这两周遇到的坑记录如下

 

需求1:指静脉过程中不要弹框

需求2:兼容知能易通的指静脉仪(注:知能易通是曙光易通的旧版本,现早不提供)

 

需求1的解决:

  先请求厂家帮助提供无弹框的dll,结果又几率仍然弹框,所以换成我用java来写

  需求如下:1.程序检测窗口出现拍摄登录图像等字样,发送回车命令 2.随客户端启动 

       使用的jna框架调用user32命令,在执行中可以加入循环,判断electron标题,如果标题不存在,即关闭,结束循环,关闭程序

package yinhai.com;

import com.sun.jna.Native;

public interface User32 extends W32API {
    User32 INSTANCE = (User32) Native.loadLibrary("user32", User32.class, DEFAULT_OPTIONS);
    
    boolean ShowWindow(HWND hWnd, int nCmdShow);
    
    boolean SetForegroundWindow(HWND hWnd);
    
    HWND FindWindow(String winClass, String title);
    
    HWND FindWindow(int winClass, String title);
    
    HWND FindWindowEx(HWND hWnd, HWND childWnd, int wParam, int lParam);
    
    HWND FindWindowEx(HWND hWnd, int childWnd, int wParam, int lParam);
    
    boolean PostMessage(HWND hWnd, Integer Msg, Integer wParam, Integer lParam);
    
    boolean PostMessage(HWND hWnd, int Msg, int wParam, int lParam);
    
    boolean PostMessage(HWND hWnd, String Msg, int wParam, int lParam);
    
    boolean PostMessage(HWND hWnd, String Msg, String wParam, String lParam);
    
    boolean PostMessage(HWND hWnd, int Msg, String wParam, String lParam);
    
    boolean PostMessage(HWND hWnd, int Msg, String wParam, int lParam);
    
    boolean PostMessage(HWND hWnd, String Msg, String wParam, int lParam);
    
    void keybd_event(String bVk, String bScan, String dwFlags, String dwExtralnfo);
    
    void keybd_event(int bVk, String bScan, String dwFlags, String dwExtralnfo);
    
    void keybd_event(String bVk, int bScan, int dwFlags, int dwExtralnfo);
    
    void keybd_event(int bVk, int bScan, int dwFlags, int dwExtralnfo);
    
    void keybd_event(int bVk, int bScan, String dwFlags, int dwExtralnfo);
    
    void keybd_event(String bVk, int bScan, String dwFlags, int dwExtralnfo);
    
    boolean SendMessage(HWND hWnd, Integer Msg, Integer wParam, Integer lParam);
    
    boolean SendMessage(HWND hWnd, int Msg, int wParam, int lParam);
    
    boolean SendMessage(HWND hWnd, String Msg, int wParam, int lParam);
    
    boolean SendMessage(HWND hWnd, String Msg, String wParam, String lParam);
    
    boolean SendMessage(HWND hWnd, int Msg, String wParam, String lParam);
    
    boolean SendMessage(HWND hWnd, int Msg, String wParam, int lParam);
    
    boolean SendMessage(HWND hWnd, String Msg, String wParam, int lParam);
}
定义user32dll接口
package yinhai.com;

import java.util.HashMap;
import java.util.Map;
import com.sun.jna.FromNativeContext;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.PointerType;
import com.sun.jna.win32.StdCallLibrary;
import com.sun.jna.win32.W32APIFunctionMapper;
import com.sun.jna.win32.W32APITypeMapper;

@SuppressWarnings({ "unchecked", "serial" })
public interface W32API extends StdCallLibrary {
    Map UNICODE_OPTIONS = new HashMap() {
        private static final long serialVersionUID = 1L;
        {
            put(OPTION_TYPE_MAPPER, W32APITypeMapper.UNICODE);
            put(OPTION_FUNCTION_MAPPER, W32APIFunctionMapper.UNICODE);
        }
    };
    Map ASCII_OPTIONS = new HashMap() {
        {
            put(OPTION_TYPE_MAPPER, W32APITypeMapper.ASCII);
            put(OPTION_FUNCTION_MAPPER, W32APIFunctionMapper.ASCII);
        }
    };
    Map DEFAULT_OPTIONS = Boolean.getBoolean("w32.ascii") ? ASCII_OPTIONS : UNICODE_OPTIONS;
    
    public static class HANDLE extends PointerType {
        public Object fromNative(Object nativeValue, FromNativeContext context) {
            Object o = super.fromNative(nativeValue, context);
            if (INVALID_HANDLE_VALUE.equals(o))
                return INVALID_HANDLE_VALUE;
            return o;
        }
    }
    
    public static class HWND extends HANDLE {
    }
    
    HANDLE INVALID_HANDLE_VALUE = new HANDLE() {
        {
            super.setPointer(Pointer.createConstant(-1));
        }
        
        public void setPointer(Pointer p) {
            throw new UnsupportedOperationException("Immutable reference");
        }
    };
}
W32API
package yinhai.com;

import java.io.IOException;

import javax.swing.JOptionPane;

public class ListenerWindow {
    
    public static void main(String[] args) {
        

        W32API.HWND targetHwnd=null;
        
        W32API.HWND hwnd;
        W32API.HWND ytjHwnd;
        W32API.HWND ytjErrorHwnd;
        W32API.HWND ytjFallHwnd;
        
        // 循环监听一体机窗口
        boolean ytjState = true;
        
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        
        while (ytjState) {
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            hwnd = User32.INSTANCE.FindWindow(0, "拍摄登录图像");
            ytjHwnd = User32.INSTANCE.FindWindow(0, "生存认证指静脉离线采集程序");
            ytjErrorHwnd = User32.INSTANCE.FindWindow(0, "Sugon");
            ytjFallHwnd = User32.INSTANCE.FindWindow(0, "信息提示");
            
            // W32API.HWND hwnd = User32.INSTANCE.FindWindow(0, "Sugon");
            // W32API.HWND childHwnd = User32.INSTANCE.FindWindowEx(hwnd, 0, 0,
            // 0);
            // User32.INSTANCE.SetForegroundWindow(hwnd);
            /*
             * for (int i = 0; i < 100; i++) { // keyPress(82); //
             * //User32.INSTANCE.PostMessage(hwnd, // 82, 0,0);
             * backKeyPress(childHwnd, 82); }
             */
            // System.out.println("运行中");
            if (hwnd != null||ytjErrorHwnd != null||ytjFallHwnd != null) {
                if(hwnd!=null) {
                    targetHwnd=hwnd;
                    hwnd=null;
                }else if(ytjErrorHwnd!=null){
                    targetHwnd=ytjErrorHwnd;
                    ytjErrorHwnd=null;
                }else if(ytjFallHwnd!=null){
                    targetHwnd=ytjFallHwnd;
                    ytjFallHwnd=null;
                }
                User32.INSTANCE.ShowWindow(targetHwnd, 9);
                User32.INSTANCE.SetForegroundWindow(targetHwnd);
                // 发送回车命令
                User32.INSTANCE.PostMessage(targetHwnd, 256, 0xD, 0);
            }
            
            /*//关闭
            if (ytjHwnd == null) {
                // System.out.println("no exe");
                //JOptionPane.showMessageDialog(null, "辅助采集程序关闭", "指静脉离线程序", JOptionPane.ERROR_MESSAGE);
                ytjState = false;
            }*/
            
            /*
             * if (hwnd != null) { User32.INSTANCE.ShowWindow(hwnd, 9);
             * User32.INSTANCE.SetForegroundWindow(hwnd); } else { try {
             * System.out.println(" can't find the window !!");
             * Runtime.getRuntime().exec("NotePad.exe"); } catch (IOException e)
             * { e.printStackTrace(); } }
             */
        }
    }
    
    public static void backKeyPress(W32API.HWND hwnd, int keyNum) {
        User32.INSTANCE.PostMessage(hwnd, 256, keyNum, 0);
    }
    
    public static void backKeyRelease(W32API.HWND hwnd, int keyNum) {
        User32.INSTANCE.PostMessage(hwnd, 257, keyNum, 0);
    }
    
    public static void keyPress(int keyNum) {
        User32.INSTANCE.keybd_event(keyNum, 0, 0, 0);
        User32.INSTANCE.keybd_event(keyNum, 0, "KEYEVENTF_KEYUP", 0);
    }
}
主方法

接着为了扩展项目通用性,把java18的32和64位的jre包提取出来,然后写了一个bat隐藏启动(如下图)

然后在electron的main.js中让在加载中调用bat

//加载cmd命令
var execState=new Boolean(true);
const exec = require('child_process');

//在基本命令加载完后再启动cmd加载
app.on('will-finish-launching',() => {
    if(execState==true){
    runExec(execState); // 生效啦,可以做些什么执行一种相对的同步状态,例如判断输出内容到什么了    
    execState=false;
    }    
});


// 任何你期望执行的cmd命令,ls都可以
let cmdStr = "start.bat";//'./你的可执行程序名称 -p 需要输入密码的话'
// 执行cmd命令的目录,如果使用cd xx && 上面的命令,这种将会无法正常退出子进程 
let cmdPath =  process.cwd()+"\\resources\\app\\jar";
// 子进程名称
let workerProcess

function runExec() {
        exec.execFile(cmdStr, [], {cwd:cmdPath}, function(error, stdout, stderr) {
            console.log(error);
            console.log(stdout);
        });
main.js 的主要修改项

 

接下来讲讲知能易通和曙光易通指静脉仪的坑

  首先要知道知能易通和曙光易通是一个公司,曙光易通是知能易通的升级版

直接说解决方法:

  1.找厂家要最新版的驱动,我用的是5.0.0.3NoP-AC,然后必须连上曙光易通的静脉仪,卸载旧驱动,安装新驱动

  2.使用CoorperateRegistTool.exe给程序生成reg文件

  3.如果电脑是32位,需用管理员身份运行reg.reg,如果电脑是64位,

  需用管理员运行 C:\Windows\SysWOW64目录下的cmd.exe,输入 reg import 路径\reg.reg

  4.从驱动的安装demo下把dll拷出来,调用dll获取控件版本返回的是-1,但其实是获取了,获得的值与页面调html调ocx控件返回的值不同

  5.然后除了获取指纹模板其他方法可以不变,方法如下图

  尽管开发完成,但是在使用过程中仍然能明显感到使用的吃力,如1:N认证时返回255,无法确定最佳手指位置,最后作为了认证失败处理

      

 

posted on 2019-03-28 17:04  黑狱  阅读(1232)  评论(1编辑  收藏  举报