简体   繁体   English

在 JNA 中传递参数

[英]Passing parameter in JNA

This code fills a generated data structure SCANNER_FULL_PLUS_EX and then calls a function ScanReadFull_PlusEx().此代码填充生成的数据结构 SCANNER_FULL_PLUS_EX,然后调用 function ScanReadFull_PlusEx()。 Both are generated by JNAerator and supposed to create some files like Scan_F.bmp etc.两者都是由JNAerator生成的,应该创建一些文件,如 Scan_F.bmp 等。

For 64 bit java on windows 10 6-bit the file names in byte[512] do not pass properly to the dll.对于 windows 上的64 位 java 10 6 位,字节 [512] 中的文件名无法正确传递给 dll。 Most of the time file names are null大多数时候文件名是null

    public short SCANTEST(String fileName) {

        StringBuilder BitmapNameF = new StringBuilder();
        StringBuilder BitmapNameR = new StringBuilder();
        StringBuilder BitmapNameF_IR = new StringBuilder();
        StringBuilder BitmapNameR_IR = new StringBuilder();
        StringBuilder BitmapNameF_UV = new StringBuilder();
        StringBuilder BitmapNameR_UV = new StringBuilder();

        SCANNER_FULL_PLUS_EX m_ScanFullPlusEx = new SCANNER_FULL_PLUS_EX();

        m_ScanFullPlusEx.Version = 0;
        m_ScanFullPlusEx.BrightnessFront = 100;
        m_ScanFullPlusEx.ThresholdFront = 100;
        m_ScanFullPlusEx.BrightnessRear = 100;
        m_ScanFullPlusEx.ThresholdRear = 100;
        m_ScanFullPlusEx.BitsPerPixel = 8;
        m_ScanFullPlusEx.ScanMode = 2;

        m_ScanFullPlusEx.ScanModeIR = 0;
        m_ScanFullPlusEx.ScanModeUV = 0;

        m_ScanFullPlusEx.dwImageWidth = 0;
        m_ScanFullPlusEx.dwImageHeight = 0;

        m_ScanFullPlusEx.pImageFront = new NativeLong(0);
        m_ScanFullPlusEx.dwImageSizeFront = 0;
        m_ScanFullPlusEx.pImageRear = new NativeLong(0);
        m_ScanFullPlusEx.dwImageSizeRear = 0;
        m_ScanFullPlusEx.pIR_ImageFront = new NativeLong(0);
        m_ScanFullPlusEx.dwIR_ImageSizeFront = 0;
        m_ScanFullPlusEx.pIR_ImageRear = new NativeLong(0);
        m_ScanFullPlusEx.dwIR_ImageSizeRear = 0;
        m_ScanFullPlusEx.pUV_ImageFront = new NativeLong(0);
        m_ScanFullPlusEx.dwUV_ImageSizeFront = 0;
        m_ScanFullPlusEx.pUV_ImageRear = new NativeLong(0);
        m_ScanFullPlusEx.dwUV_ImageSizeRear = 0;

        BitmapNameF.append(fileName + "F.bmp");
        BitmapNameR.append(fileName + "R.bmp");
        BitmapNameF_IR.append(fileName + "F_IR.bmp");
        BitmapNameR_IR.append(fileName + "R_IR.bmp");
        BitmapNameF_UV.append(fileName + "F_UV.bmp");
        BitmapNameR_UV.append(fileName + "R_UV.bmp");

        m_ScanFullPlusEx.ImageNameRear = Native.toByteArray(BitmapNameR.toString());
        m_ScanFullPlusEx.ImageNameFront = Native.toByteArray(BitmapNameF.toString());
        m_ScanFullPlusEx.IR_ImageNameFront = Native.toByteArray(BitmapNameF_IR.toString());
        m_ScanFullPlusEx.IR_ImageNameRear = Native.toByteArray(BitmapNameR_IR.toString());
        m_ScanFullPlusEx.UV_ImageNameFront = Native.toByteArray(BitmapNameF_UV.toString());
        m_ScanFullPlusEx.UV_ImageNameRear = Native.toByteArray(BitmapNameR_UV.toString());

        // wrap in 512 buffer
        byte[] f1 = new byte[512]; for (int i=0; i<m_ScanFullPlusEx.ImageNameRear.length;i++) f1[i]=m_ScanFullPlusEx.ImageNameRear[i]; m_ScanFullPlusEx.ImageNameRear = f1;
        byte[] f2 = new byte[512]; for (int i=0; i<m_ScanFullPlusEx.ImageNameFront.length;i++) f2[i]=m_ScanFullPlusEx.ImageNameFront[i]; m_ScanFullPlusEx.ImageNameFront = f2;
        byte[] f3 = new byte[512]; for (int i=0; i<m_ScanFullPlusEx.IR_ImageNameFront.length;i++) f3[i]=m_ScanFullPlusEx.IR_ImageNameFront[i]; m_ScanFullPlusEx.IR_ImageNameFront = f3;
        byte[] f4 = new byte[512]; for (int i=0; i<m_ScanFullPlusEx.IR_ImageNameRear.length;i++) f4[i]=m_ScanFullPlusEx.IR_ImageNameRear[i]; m_ScanFullPlusEx.IR_ImageNameRear = f4;
        byte[] f5 = new byte[512]; for (int i=0; i<m_ScanFullPlusEx.UV_ImageNameFront.length;i++) f5[i]=m_ScanFullPlusEx.UV_ImageNameFront[i]; m_ScanFullPlusEx.UV_ImageNameFront = f5;
        byte[] f6 = new byte[512]; for (int i=0; i<m_ScanFullPlusEx.UV_ImageNameRear.length;i++) f6[i]=m_ScanFullPlusEx.UV_ImageNameRear[i]; m_ScanFullPlusEx.UV_ImageNameRear = f6;

        short ret = MB2Library.INSTANCE.ScanReadFull_PlusEx(ByteBuffer.wrap(Native.toByteArray(gPort.Global)), m_ScanFullPlusEx, MB2Library.SCAN_OUTPUT_FORMAT_FILE_BMP);

        return ret;
    }

C header file for the structure. C header 文件的结构。

typedef struct
{
        int Version;
        int BrightnessFront;
        int ThresholdFront;

        int BrightnessRear;
        int ThresholdRear;
        int BitsPerPixel;

        int ScanMode;   // Front/Rear/Front-Rear
        int ScanModeIR; // ( not yet implemented ) IR Front/Rear/Front-Rear
        int ScanModeUV; // ( not yet implemented ) UV Front/Rear/Front-Rear

        DWORD dwImageWidth;
        DWORD dwImageHeight;

        // Front CIS Image
        HANDLE pImageFront;
        DWORD dwImageSizeFront;

        // Rear CIS Image
        HANDLE pImageRear;
        DWORD dwImageSizeRear;

        // Front IR Image
        HANDLE pIR_ImageFront;
        DWORD dwIR_ImageSizeFront;

        // Rear IR Image
        HANDLE pIR_ImageRear;
        DWORD dwIR_ImageSizeRear;

        // Front UV Image
        HANDLE pUV_ImageFront;
        DWORD dwUV_ImageSizeFront;

        // Rear UV Image
        HANDLE pUV_ImageRear;
        DWORD dwUV_ImageSizeRear;

        // images path
        TCHAR ImageNameFront[512];
        TCHAR ImageNameRear[512];
        TCHAR IR_ImageNameFront[512];
        TCHAR IR_ImageNameRear[512];
        TCHAR UV_ImageNameFront[512];
        TCHAR UV_ImageNameRear[512];

} SCANNER_FULL_PLUS_EX;

typedef SCANNER_FULL_PLUS_EX *PSCANNER_FULL_PLUS_EX;

EDIT 1:编辑1:

package mb2;

import java.util.StringTokenizer;

import java.util.Arrays;
import java.util.List;

import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.NativeLibrary;
import com.sun.jna.NativeLong;
import com.sun.jna.Pointer;
import com.sun.jna.Structure;
import com.sun.jna.ptr.ByReference;
import com.sun.jna.ptr.PointerByReference;
import com.sun.jna.ptr.IntByReference;
import com.sun.jna.ptr.ByteByReference;
import com.sun.jna.ptr.DoubleByReference;
import com.sun.jna.ptr.FloatByReference;
import com.sun.jna.ptr.LongByReference;
import com.sun.jna.ptr.NativeLongByReference;
import com.sun.jna.ptr.ShortByReference;

public class SCANNER_FULL_PLUS_EX extends Structure {
    public int Version;
    public int BrightnessFront;
    public int ThresholdFront;
    public int BrightnessRear;
    public int ThresholdRear;
    public int BitsPerPixel;
    /** Front/Rear/Front-Rear */
    public int ScanMode;
    /** ( not yet implemented ) IR Front/Rear/Front-Rear */
    public int ScanModeIR;
    /** ( not yet implemented ) UV Front/Rear/Front-Rear */
    public int ScanModeUV;
    public int dwImageWidth;
    public int dwImageHeight;
    /**
     * Front CIS Image<br>
     * C type : HANDLE
     */
    public NativeLong pImageFront;
    public int dwImageSizeFront;
    /**
     * Rear CIS Image<br>
     * C type : HANDLE
     */
    public NativeLong pImageRear;
    public int dwImageSizeRear;
    /**
     * Front IR Image<br>
     * C type : HANDLE
     */
    public NativeLong pIR_ImageFront;
    public int dwIR_ImageSizeFront;
    /**
     * Rear IR Image<br>
     * C type : HANDLE
     */
    public NativeLong pIR_ImageRear;
    public int dwIR_ImageSizeRear;
    /**
     * Front UV Image<br>
     * C type : HANDLE
     */
    public NativeLong pUV_ImageFront;
    public int dwUV_ImageSizeFront;
    /**
     * Rear UV Image<br>
     * C type : HANDLE
     */
    public NativeLong pUV_ImageRear;
    public int dwUV_ImageSizeRear;
    /**
     * images path<br>
     * C type : TCHAR[512]
     */
    public byte[] ImageNameFront = new byte[512];
    /** C type : TCHAR[512] */
    public byte[] ImageNameRear = new byte[512];
    /** C type : TCHAR[512] */
    public byte[] IR_ImageNameFront = new byte[512];
    /** C type : TCHAR[512] */
    public byte[] IR_ImageNameRear = new byte[512];
    /** C type : TCHAR[512] */
    public byte[] UV_ImageNameFront = new byte[512];
    /** C type : TCHAR[512] */
    public byte[] UV_ImageNameRear = new byte[512];
    public SCANNER_FULL_PLUS_EX() {
        super();
    }
    protected List<String> getFieldOrder() {
        return Arrays.asList("Version", "BrightnessFront", "ThresholdFront", "BrightnessRear", "ThresholdRear", "BitsPerPixel", "ScanMode", "ScanModeIR", "ScanModeUV", "dwImageWidth", "dwImageHeight", "pImageFront", "dwImageSizeFront", "pImageRear", "dwImageSizeRear", "pIR_ImageFront", "dwIR_ImageSizeFront", "pIR_ImageRear", "dwIR_ImageSizeRear", "pUV_ImageFront", "dwUV_ImageSizeFront", "pUV_ImageRear", "dwUV_ImageSizeRear", "ImageNameFront", "ImageNameRear", "IR_ImageNameFront", "IR_ImageNameRear", "UV_ImageNameFront", "UV_ImageNameRear");
    }
    public SCANNER_FULL_PLUS_EX(Pointer peer) {
        super(peer);
    }
    public static class ByReference extends SCANNER_FULL_PLUS_EX implements Structure.ByReference {

    };
    public static class ByValue extends SCANNER_FULL_PLUS_EX implements Structure.ByValue {

    };
}

Welcome to the wonderful world of character encoding .欢迎来到字符编码的奇妙世界。

You're using Native.toByteArray() with only the String argument.您仅使用带有String参数的Native.toByteArray() This returns:这将返回:

A NUL-terminated byte buffer equivalent to the given String, using the encoding returned by getDefaultStringEncoding().与给定字符串等效的以 NUL 结尾的字节缓冲区,使用 getDefaultStringEncoding() 返回的编码。

It is generally a bad practice to leave encoding unspecified when converting between Strings and byte arrays.在字符串和字节 arrays 之间进行转换时,不指定编码通常是一种不好的做法。 In this case, you actually do want the default system encoding but it's useful to specify that, and, in the process, understand what it's doing.在这种情况下,您实际上确实需要默认系统编码,但指定它很有用,并且在此过程中,了解它在做什么。

The default Windows encoding is UTF-16, which uses 16 bits to represent characters ( wchar_t in C).默认的 Windows 编码是 UTF-16,它使用 16 位来表示字符(C 中的wchar_t )。 For ASCII character strings, like the ones you are using, that means your byte array ends up with alternating 0 bytes and 8-bit character bytes.对于 ASCII 字符串,就像您正在使用的字符串一样,这意味着您的字节数组以交替的 0 字节和 8 位字符字节结束。 (Feel free to instrument your code and output Arrays.toString(f1) to see this for yourself!) (请随意检测您的代码和 output Arrays.toString(f1)自己看看这个!)

The C structure uses arrays of TCHAR . C 结构使用TCHAR的 arrays 。 This can be either a single byte or two bytes, depending on your encoding (which will match Native.toByteArray() ).这可以是单个字节或两个字节,具体取决于您的编码(将匹配Native.toByteArray() )。

So the default encoding here is fine, except that you do need to know what that encoding is, in order to properly size your structure.所以这里的默认编码很好,除了你需要知道那个编码是什么,以便正确调整你的结构。 You are passing 512-byte arrays when you probably need 512-TCHAR arrays (1024 bytes).当您可能需要 512-TCHAR arrays(1024 字节)时,您正在传递 512 字节 arrays。

JNA structures must know their total byte size, however, and TCHAR isn't mapped in JNA.但是,JNA 结构必须知道它们的总字节大小,并且TCHAR未映射到 JNA 中。 So you have to figure out CHAR_WIDTH and multiply 512 by that value in the structure.因此,您必须计算出CHAR_WIDTH并将 512 乘以结构中的该值。 (Search JNA source code for CHAR_WIDTH for ample examples of this.) (在 JNA 源代码中搜索CHAR_WIDTH以获得大量示例。)

(EDIT 1) (编辑 1)

Thanks for providing the JNA mapping.感谢您提供 JNA 映射。 Generally the very first thing to look at when a JNA-mapped function/structure misbehaves is the type mapping.通常,当 JNA 映射的函数/结构行为不端时,首先要查看的是类型映射。 In your case, in addition to the incorrect TCHAR mapping to byte as described above, you have mapped the HANDLE as a NativeLong .在您的情况下,除了上述错误的TCHAR映射到byte之外,您还将HANDLE映射为NativeLong This doesn't work on Windows: HANDLE extends from PointerType and Pointers match operating system bitness, so are 64-bit on 64-bit Windows.这在 Windows 上不起作用: HANDLEPointerType扩展,并且指针匹配操作系统位数,64 位 Windows 上的 64 位也是如此。 Windows LONG on the other hand (and thus NativeLong on Windows) is always a 32-bit type.另一方面,Windows LONG (因此在 Windows 上为NativeLong )始终是 32 位类型。

So to summarize, you need (at least) the following changes:总而言之,您需要(至少)以下更改:

  1. Change the HANDLE types to map to JNA's WinNT.HANDLE classHANDLE类型更改为 map 为 JNA 的WinNT.HANDLE class

  2. Change the TCHAR byte width to match character width.更改TCHAR字节宽度以匹配字符宽度。 One way to do this is to insert this at the top of your class (or anywhere in your project, public so it's accessible):一种方法是将其插入 class 的顶部(或项目中的任何位置,公开,以便访问):

     private static final int CHAR_WIDTH = Boolean.getBoolean("w32.ascii")? 1: 2;

Then in your byte[] declarations, multiply 512 * CHAR_WIDTH to get the correct width.然后在您的byte[]声明中,乘以512 * CHAR_WIDTH以获得正确的宽度。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM