Указатель на указатель на структуру в качестве аргумента в JNA

2

У сторонней DLL есть функция, которая ожидает указатель на указатель на структуру как аргумент:

__declspec(dllimport) int __stdcall
SegmentImages( unsigned char* imageData, int imageWidth, int imageHeight,
               int* numOfFinger, SlapInfo** slapInfo, const char* outFilename );

Он сегментирует "пощечину" изображение отпечатков пальцев numOfFinger (обычно 4) на отдельные отпечатки пальцев (outFilename + число пальцев).

Определение SlapInfo:

struct SlapInfo {
    int fingerType; 
    Point fingerPosition[4];
    int imageQuality;
    int rotation;
    int reserved[3];
};

struct Point {
    int x;
    int y;
};

Отрывок из примера в C:

unsigned char* imageData;
int imageWidth, imageHeight;
//obtain imageData, imageWidth and imageHeight from scanner...
int numOfFinger;
SlapInfo* slapInfo;

int result = SegmentImages( imageData, imageWidth, imageHeight, &numOfFinger,
                            &slapInfo, FINGER_IMG_PATH);

ЮНА

Согласно FAQ JNA, в моем случае я должен использовать "Structure.ByReference []":

void myfunc(simplestruct** data_array, int count); // use Structure.ByReference[]

Итак, я сопоставлен в Java/JNA следующим образом:

сооружения

public class Point extends Structure {
    public int x;
    public int y;

    public Point(){
        super();
    }

    @Override
    protected List<String> getFieldOrder() {
        return Arrays.asList("x", "y");
    }
}


public class SlapInfo extends Structure {    
    public int fingerType;
    public Point[] fingerPosition = new Point[4];
    public int imageQuality;
    public int rotation;
    public int[] reserved = new int[3];

    public SlapInfo() {
        super();
    }

    public SlapInfo(Pointer pointer){
        super(pointer);
    }

    @Override
    protected List<String> getFieldOrder() {
        return Arrays.asList("fingerType", "fingerPosition", "imageQuality",
                "rotation", "reserved");
    }

    public static class ByReference extends SlapInfo implements Structure.ByReference { }
}

функция

int SegmentImages(byte[] imageData, int imageWidth, int imageHeight, 
                  IntByReference numOfFinger, SlapInfo.ByReference[] slapInfo,
                  String outFileName);

использование

//imageData, width and height are with valid values
IntByReference nrOfFingers = new IntByReference();
SlapInfo.ByReference[] slapInfoArray = (SlapInfo.ByReference[]) 
                new SlapInfo.ByReference().toArray(4);
                //Usually, there are 4 fingers in a slap, but the correct
                //value should be the returned in nrOfFingers

int result = lib.SegmentImages(imageData, width, height,
                nrOfFingers, slapInfoArray, FINGER_IMG_PATH);

Но с этим методом я получаю ошибку:

java.lang.Error: Invalid memory access
        at com.sun.jna.Native.invokeInt(Native Method)
        at com.sun.jna.Function.invoke(Function.java:419)
        at com.sun.jna.Function.invoke(Function.java:354)
        at com.sun.jna.Library$Handler.invoke(Library.java:244)
        at com.sun.proxy.$Proxy0.SegmentImages(Unknown Source)
        at scanners.JNAScanner.segmentToFile(JNAScanner.java:366)

Я также пробовал:

Во всех случаях я получил сообщение об ошибке "Недопустимый доступ к памяти".

Что я делаю неправильно?

  • 0
    Обратите внимание на __stdcall в объявлении функции C - ваша библиотека не использует соглашение о вызовах cdecl. Ваш интерфейс библиотеки расширяет StdCallLibrary ?
  • 0
    Хм, я пытаюсь воспроизвести неверный доступ к памяти, но не могу. Вы уверены, что выделили достаточно большой slapInfoArray ? Но с другой стороны, пример C выделяет только указатель, предполагая, что функция может заменить указатель массивом, который она выделяет сама. Почти невозможно высказать предположения о том, что может пойти не так без доступа к библиотеке или ее документации.
Показать ещё 3 комментария
Теги:
pointers
jna

1 ответ

1

Если SegmentImages возвращает адрес одной или нескольких структур в slapInfo, вам нужно использовать PointerByReference. Фактическим нативным типом является struct **, но значение, которое вы возвращаете в slapInfo является указателем.

IntegerByReference iref = new IntegerByReference();
PointerByReference pref = new PointerByReference();
int result = SegmentImages(..., iref, pref, ...);

Если структуры возвращаются в одном блоке, вы можете сделать это:

SlapInfo s = new SlapInfo(pref.getValue());
SlapInfo[] slaps = s.toArray(iref.getValue());

Ещё вопросы

Сообщество Overcoder
Наверх
Меню