Передача параметра в JNA - PullRequest
1 голос
/ 17 июня 2020

Этот код заполняет сгенерированную структуру данных SCANNER_FULL_PLUS_EX, а затем вызывает функцию ScanReadFull_PlusEx (). Оба генерируются JNAerator и должны создавать некоторые файлы, такие как Scan_F.bmp et c.

Для 64 бит java на windows 10 6 -bit имена файлов в байте [512] не передаются должным образом в dll. В большинстве случаев имена файлов: 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 заголовочный файл для структуры.

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:

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 {

    };
}

1 Ответ

0 голосов
/ 17 июня 2020

Добро пожаловать в чудесный мир кодировки символов .

Вы используете Native.toByteArray () только с аргументом String. Это возвращает:

байтовый буфер с завершающим нулем, эквивалентный заданной строке, с использованием кодировки, возвращаемой getDefaultStringEncoding ().

Как правило, оставлять кодировка не указана при преобразовании между строками и байтовыми массивами. В этом случае вам действительно нужна системная кодировка по умолчанию, но полезно указать это и в процессе понять, что он делает.

Кодировка Windows по умолчанию - UTF-16, которая использует 16 биты для представления символов (wchar_t в C). Для символьных строк ASCII, подобных тем, которые вы используете, это означает, что ваш байтовый массив заканчивается чередованием байтов 0 и 8-битных символов. (Не стесняйтесь инструментировать свой код и вывести Arrays.toString(f1), чтобы убедиться в этом сами!)

Структура C использует массивы TCHAR. Это может быть один или два байта, в зависимости от вашей кодировки (которая соответствует Native.toByteArray()).

Таким образом, кодировка по умолчанию здесь подходит, за исключением того, что вам нужно знать, что это за кодировка, чтобы правильно определить размер вашей структуры. Вы передаете 512-байтовые массивы, когда вам, вероятно, нужны массивы 512-TCHAR (1024 байта). Однако

структуры JNA должны знать свой общий размер в байтах, а TCHAR не отображается в JNA. Итак, вам нужно вычислить CHAR_WIDTH и умножить 512 на это значение в структуре. (Найдите в исходном коде JNA CHAR_WIDTH, чтобы найти достаточное количество примеров этого.)

(EDIT 1)

Спасибо за предоставление сопоставления JNA. Обычно самое первое, на что следует обратить внимание, когда JNA-отображенная функция / структура плохо себя ведет, - это отображение типов. В вашем случае, в дополнение к неправильному сопоставлению TCHAR с byte, как описано выше, вы сопоставили HANDLE как NativeLong. Это не работает с Windows: HANDLE расширяется от PointerType, а указатели соответствуют разрядности операционной системы, поэтому 64-разрядные на 64-разрядных Windows. Windows LONG с другой стороны (и, следовательно, NativeLong на Windows) всегда 32-битный тип.

Итак, чтобы подвести итог, вам потребуются (как минимум) следующие изменения:

  1. Измените типы HANDLE для сопоставления с WinNT.HANDLE классом JNA

  2. Измените ширину TCHAR байта в соответствии с шириной символа. Один из способов сделать это - вставить это в начало вашего класса (или где угодно в вашем проекте, publi c, чтобы он был доступен):

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

Затем в вашем byte[] объявления, умножьте 512 * CHAR_WIDTH, чтобы получить правильную ширину.

...