Как передать int как параметр функции C ++ из Java, используя JNA

В настоящее время я работаю над проектом, который требует разработки нативной DLL (в C ++) для доступа к приложению Java. Я выбрал JNA для работы моста, и у меня возникают проблемы с передачей правильных значений int из Java в функции C ++.

Проще говоря, у меня есть функция, которая принимает значение int в качестве параметра в C ++:
(код удаляется, а методы переименовываются для сохранения конфиденциальности)

JAVALINK_EXPORT SomeStructure WINAPI GetSomeStructureFromIndex(int index) {
std::string debugMsg("Received index of ");
debugMsg.append(toString(index));
OutputDebugString(debugMsg.c_str());
SomeStructure result = defaultStructure;
if (index >= 0 && index < structListSize)
result = structList[index];

return result;
}

toString это простой метод, который преобразует значение любого типа данных в std::string используя std::stringstream, Реализация заключается в следующем:

template <class T>
inline std::string toString (const T& t) {
std::stringstream ss;
ss << t;
return ss.str();
}

SomeStructure переименован из фактической структуры, которую я использую в коде. structList это массив SomeStructure, structListSize а также structList все глобальные переменные в разделяемой памяти.

Это сигнатура метода в интерфейсе Java для DLL:

SomeStructure.ByValue GetSomeStructureFromIndex(int index);

Вот как я использую метод в Java для теста:

SomeStructure.ByValue received = library.GetSomeStructureFromIndex(1);

library это экземпляр интерфейса для файла DLL (подкласс StdCallLibrary) создан с использованием Native.loadLibrary, Когда приведенный выше код выполняется в Java, я получаю что-то вроде следующего вывода в моем выводе отладки Windows:

Received index of 86701080

(Затем программа перейдет к ошибке нарушения прав доступа, если я пропустил проверку index с линией if (index >= 0 && index < structListSize) до получения структуры из массива)

86701080 может быть любым произвольным значением. Я понял, что это меняется в зависимости от сигнатуры экспортируемой функции. Я что-то здесь упускаю? Функция правильно получает ожидаемое значение 1 была подпись функции void PrintIndex(int index)

РЕДАКТИРОВАТЬ (0): я изменил пример кода для более точного соответствия с реальным кодом.

РЕДАКТИРОВАТЬ (1): В соответствии с указателями @ technomage я начал использовать ByValue для всех сигнатур методов и переменных, собирающих возвращаемые структуры.

РЕДАКТИРОВАТЬ (2): класс Java SomeStructure имеет дополнительную переменную и метод Java по сравнению с SomeStructure структура в C ++. В настоящее время я проверяю, является ли это причиной расхождения.

ЗАДАЧА РЕШЕНА

@technomage пояснил, что для того, чтобы функция C ++ могла интерпретировать свои аргументы и возвращаемые значения так, как ожидается, размер структуры, используемой в качестве возвращаемого типа (а также в качестве параметров функции), не должен отличаться от ее Java-аналога. Это может быть проверено, в случае SomeStructureв C ++ с sizeof(SomeStructure) и в Java с SomeStructure.size(),

В основном, случилось то, что SomeStructure Структура имеет другой размер, чем ее представление Java. SomeStructure содержит массив фиксированной длины, как показано в коде ниже:

#define MAX_LIST_SIZE 256
typedef struct {
int list[MAX_LIST_SIZE];
int length;
} SomeStructure;

Однако в представлении Java не указан размер массива фиксированной длины. list был инициализирован, чтобы содержать одно значение 0,

package model;

import com.sun.jna.Structure;

public class SomeStructure extends Structure {
public static class ByValue extends SomeStructure implements Structure.ByValue { }
public int[] list = {0};
public int length = 0;
}

Я решил проблему, заменив неверный оператор инициализации следующим:

private static final int MAX_LIST_SIZE = 256;
public int[] list = new int[MAX_LIST_SIZE];

Заметка: Целочисленная константа MAX_LIST_SIZE объявлен private сохранить его только для Java.

После внесения всех этих изменений мой код работает нормально и больше не сталкивается с нарушениями доступа.

2

Решение

«WINAPI» подразумевает соглашение о вызовах stdcall, но вам нужно убедиться в локальном определении макроса. Если это так, вам нужно StdCallLibrary вместо Library, Это может повлиять на ваш входящий index аргумент.

Вы также копируете свою структуру (по семантике значения), а не указатель на нее. Когда вы передаете структуру по значению или возвращаете структуру по значению, вам необходимо скажи JNA, что ты так делаешь.

РЕДАКТИРОВАТЬ

Удостовериться SomeStructure.size() соответствует родной sizeof(SomeStructure), Обычно структуры, возвращаемые по значению, реализуются таким образом, что вызывающая сторона выделяет память в стеке и передает неявный указатель вызываемому объекту, который затем записывает в эту память. Если вызывающая сторона и вызываемая сторона не согласны с размером этой памяти, это может повлиять на другие вещи в стеке (такие как аргументы и возвращаемые значения). Вы также можете добавить еще несколько аргументов в функцию и распечатать их значения (в шестнадцатеричном виде), чтобы получить приблизительное значение того, что находится в стеке. Если вы передаете узнаваемые аргументы (например, 0x12345678), часто становится ясно, что толкает или тянет стек в неправильном направлении.

1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]