Marshal.StructureToPtr эквивалент Java в JNA

#java #c# #jna

#java #c# #jna

Вопрос:

Я работаю над проектом, в котором единственная библиотека, с которой я должен взаимодействовать, — это DLL-файл, а ресурс, который у меня есть, — это рабочий проект C # с исходным кодом; Я использую JNA для доступа к собственным кодам, и в настоящее время я сталкиваюсь с недопустимым доступом к памяти при вызове метода;

c # код:

 [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]  
public struct RSSlapInfo
{
    public int fingerType;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
    public RSPoint[] fingerPosition;
    public int imageQuality;
    public int rotation;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
    public int[] reserved;
};

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct RSSlapInfoArray
{
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
    public RSSlapInfo[] RSSlapInfoA;
};

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct RSPoint
{
    public int x;
    public int y;
};

RSSlapInfoArray slapInfoA = new RSSlapInfoArray();
IntPtr slapInfoArray;

int _size = Marshal.SizeOf(typeof(RSSlapInfoArray));
slapInfoArray = Marshal.AllocHGlobal(_size);
Marshal.StructureToPtr(slapInfoA, slapInfoArray, true);
  

В режиме отладки я замечаю slapInfoArray изменения значений после вышеупомянутого вызова

Мой Java-код:

 public static class RSSlapInfo extends Structure
{
    public RSSlapInfo(){}
    public int fingerType;
    public RSPoint[] fingerPosition = new RSPoint[4];
    public int imageQuality;
    public int rotation;
    public int[] reserved =new int[3];
}
    
@Structure.FieldOrder({"RSSlapInfoA"})
public static class RSSlapInfoArray extends Structure implements Structure.ByValue
{
    public RSSlapInfoArray() {
    }

    public RSSlapInfo RSSlapInfoA[] = new RSSlapInfo[4];
}

@Structure.FieldOrder({"x","y"})
public static class RSPoint extends Structure
{
    public RSPoint(){
    }

    public int x;
    public int y;
}
  

В настоящее время застрял на правильном пути преобразования этой части кода C #, прежде чем я выполню собственный вызов с slapInfoArray

 RSSlapInfoArray slapInfoA = new RSSlapInfoArray();
IntPtr slapInfoArray;
    
int _size = Marshal.SizeOf(typeof(RSSlapInfoArray));
slapInfoArray = Marshal.AllocHGlobal(_size);
Marshal.StructureToPtr(slapInfoA, slapInfoArray, true);
  

Комментарии:

1. Я вижу, что вы откатили свое обновление, но хотели прокомментировать, что ключевое слово C # ref указывает, что переменные передаются по ссылке, а не по значению. Таким образом, ваше использование long и int в fingerImageData полях определенно неверно. Они должны быть указателями на значения в другом месте, например, LongByReference и т.д. IntByReference Не зная больше об API, я не могу посоветовать более подробную информацию.

Ответ №1:

Документация для Marshal.StructureToPtr() дает вам четкую подсказку о том, что вам нужно сделать:

Маршалирует данные из управляемого объекта в неуправляемый блок памяти.

structure Управляемый объект, который содержит данные, подлежащие маршалированию. Этот объект должен быть структурой или экземпляром форматированного класса.

ptr Указатель на неуправляемый блок памяти, который должен быть выделен перед вызовом этого метода.

У вас есть параметр structure, но вам нужно выделить блок памяти, необходимый для второго параметра. Это можно сделать с Memory помощью класса JNA.

Усложняя это, структура, которую вам нужно передать, на самом деле содержит массив других структур и должна быть размещена в непрерывной памяти. То, как вы сделали это в своей RSSlapInfoArray упаковке, на самом деле вообще не выделяет никакой памяти; он просто объявляет массив на стороне Java с нулевыми указателями, которые будут переданы на собственную сторону.

Первое, что вам нужно сделать, это исправить ваше RSSlapInfoArray сопоставление, чтобы распределить структурный массив последовательно. Изменить

 public RSSlapInfo RSSlapInfoA[] = new RSSlapInfo[4]; // does not allocate anything
  

Для

 public RSSlapInfo[] RSSlapInfoA = (RSSlapInfo[]) new RSSlapInfo().toArray(4); // contiguous allocation 
  

Вы должны сделать то же самое для RSPoint массива:

 public RSPoint[] fingerPosition = new RSPoint().toArray(4);
  

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

Предполагая, что вы сопоставили StructureToPtr в интерфейсе, загружающем DLL, что-то похожее на это:

 void StructureToPtr(Structure structure, Pointer ptr, boolean fDeleteOld);
  

Тогда код JNA для ваших последних 5 строк в вашем вопросе должен быть

 // Create the managed structure with the array inline
RSSlapInfoArray slapInfoA = new RSSlapInfoArray();
// Allocate a block of memory for it
Memory slapInfoArray = new Memory(slapInfoA.size());
// Call StructureToPtr
YourInterface.INSTANCE.StructureToPtr(slapInfoA, slapInfoArray, true);