Обработка распределения памяти и указателей в Electron между Node.js и C++ DLL

Я разрабатываю приложение Electron, которое требует взаимодействия с DLL C++ для управления USB-устройствами. Недавно, основываясь на рекомендациях и проблемах, возникших с node-ffi-napi (Проблема № 238), я перешел на использование koffi, другой библиотеки FFI, предназначенной для облегчения вызова функций C из сред Node.js, включая Electron.

Основная функциональность, которую я пытаюсь реализовать, включает вызов функции C++ DLL, которая выделяет память для массива структур устройств с помощью malloc, а затем возвращает указатель на этот массив. Вот прототип функции C, с которым я имею дело:

/**
 * \brief This routine allows to get ST-LINK connected probe(s).
 * \param stLinkList  : Filled with the connected ST-LINK list and its default configurations.
 * \param shared      : Enable shared mode allowing connection of two or more instances to the same ST-LINK probe.
 * \return Number of the ST-LINK probes already exists.
 */
int getStLinkList(debugConnectParameters** stLinkList, int shared);

Попытка взаимодействия с этой функцией из моего приложения Electron вызвала некоторые проблемы, особенно связанные с правильным выделением и передачей указателя на указатель (debugConnectParameters**), который DLL может использовать для выделения памяти и возврата данных.

Вот пример моего текущего подхода в Node.js с использованием koffi:

// Assuming 'lib' is the loaded DLL
const getStLinkList = lib.func('int', ['pointer', 'int']);

// Attempt to call getStLinkList
let stLinkListPtr = null; // Placeholder for a pointer to pointers
let shared = 0; // Example value for demonstration
let numberOfDevices = getStLinkList(stLinkListPtr, shared);

Мои вопросы заключаются в следующем:

Как я могу правильно выделить указатель на указатель в приложении Electron с помощью koffi, позволяя DLL выделять память и возвращать данные устройства? Как только DLL выделит память и заполнит ее структурами устройств, как мне получить доступ к этим данным и выполнить итерацию в Node.js в контексте Electron? Каковы наилучшие методы управления памятью, выделенной DLL в приложении Electron, особенно для предотвращения утечек памяти или нарушений доступа? Любые советы, фрагменты кода или ресурсы по управлению взаимодействием FFI и распределением памяти между Node.js (внутри Electron) и DLL C++ будут невероятно полезны. Меня особенно интересуют решения или примеры, рассматривающие подобные сценарии с учетом перехода от node-ffi-napi к koffi.

Я пытался связать приложение Electron с DLL C++ для управления USB-устройствами. В частности, мне нужно вызвать функцию DLL, которая выделяет массив структур для данных устройства с помощью malloc и возвращает указатель на этот массив. Я ожидал правильно выделить и передать указатель на указатель (debugConnectParameters**) на эту функцию, а затем получить доступ к данным устройства в Node.js.

Что я пробовал:

Перешел с node-ffi-napi на koffi: на основе рекомендаций и обсуждения проблемы я перешел на koffi для лучшей совместимости с Electron. Распределение указателя: предпринята попытка выделить указатель на указатель для функции DLL для выделения памяти и заполнения данными устройства, но возникли проблемы с правильной реализацией. Вызов функции: вызвал функцию DLL, ожидая, что она выделит память для массива данных устройства и сможет выполнить итерацию по нему в Node.js. Возникшие проблемы:

Неясно, как правильно выделить и инициализировать указатель на указатель для использования DLL. Возникли проблемы с доступом и управлением памятью, выделенной вызовом пост-функции DLL. Обеспокоен правильным освобождением выделенной памяти для предотвращения утечек памяти. Мне нужен совет по распределению указателей и управлению памятью для взаимодействия DLL в контексте Electron.

Обновлять

  • Я написал DLL, которая обертывает исходную DLL. Новый интерфейс не предполагает передачу указателя на память на сторону nodeJ (что, как я думал, и было причиной проблемы). Такой подход не решает проблему.
  • если я использую исходную DLL или эту новую DLL-оболочку из программы C или CPP, я получаю правильное поведение от getStLinkList(); если я вызываю любую DLL через koffi, она возвращает 0 устройств (вместо 1).

Поэтому по какой-то причине функция ведет себя некорректно при вызове из koffi напрямую или через инкапсулированную обертку.

Подозреваю, что проблема на стороне коффи, но тот факт, что функция молча выходит из строя, не помогает (никакого кода ошибки она не выдает).

В документации есть пример того, что вы пытаетесь сделать, но я не смог понять, как связать koffi.pointer с массивом динамического размера.

Botje 29.03.2024 11:37

Привет, Ботье, спасибо за интерес. Я прочитал это, но потом оно молча терпит неудачу; если я передаю нулевой указатель, я не получаю ошибок и возвращаю значение 0 (но оно должно быть 1). Сейчас я пробую другой подход, основанный на написании DLL, которая ведет себя так, как нравится Коффи: я имею в виду, что в dll не создаются адреса блоков памяти для передачи в среду узла.

wolfHasSomeProblemsHimself 29.03.2024 14:38

Вы прошли null или [null]?

Botje 29.03.2024 14:42

Я попробовал оба варианта и получил один и тот же результат. Я собираюсь добавить обновление к проблеме прямо сейчас

wolfHasSomeProblemsHimself 03.04.2024 10:07
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
4
147
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Обновление решения и объяснение

После тщательного устранения неполадок и экспериментов с различными подходами к управлению взаимодействием FFI между моим приложением Electron и C++ DLL я определил и решил основную проблему, с которой столкнулся. Вот описание проблемы и решение, которое сработало для меня:

Проблема:

  • Основной проблемой было взаимодействие с функцией C++ DLL getStLinkList(debugConnectParameters** stLinkList, int shared) из моего приложения Electron с помощью koffi. Эта функция выделяет память для массива структур устройства и возвращает указатель на этот массив.
  • Ожидалось, что функция выделит память и заполнит ее данными устройства, к которым я планировал получить доступ в Node.js в контексте Electron. Однако при вызове из приложения Electron с использованием koffi функция вернула 0, что указывает на то, что устройства не найдены, что противоречило ожидаемому поведению.
  • Первоначально я подозревал, что проблема может быть связана с тем, как память распределялась и передавалась между Node.js и DLL. Чтобы решить эту проблему, я даже написал DLL-оболочку, чтобы упростить интерфейс, но проблема осталась.

Открытие:

  • В ходе дальнейшего исследования я понял, что проблема не связана напрямую с распределением памяти или управлением указателями, как первоначально предполагалось. Вместо этого на поведение функции влиял контекст ее выполнения.
  • Вызов функции из автономного приложения C или C++ работал должным образом, правильно идентифицируя подключенные устройства. Однако вызов той же функции через koffi в приложении Electron приводил к тому, что функция не могла идентифицировать какие-либо устройства и всегда возвращала 0.

Решение:

  • Прорыв произошел, когда я сосредоточился на предварительных условиях и настройке среды, необходимых DLL для успешного выполнения getStLinkList. Оказалось, что перед вызовом getStLinkList необходимо выполнить определенные процедуры инициализации, которые изначально не были очевидны.
    • Ключом к решению была правильная настройка функций loaderPath и displayCallback перед вызовом getStLinkList. См. здесь и здесь. Эти конфигурации были критически важны для правильного выполнения функции в контексте приложения Electron, использующего koffi.
    • Реализация функций-заглушек для регистрации и отображения прогресса (как того требует DLL) и правильная настройка loaderPath были недостающими частями. Как только они были правильно настроены в среде приложения Electron, getStLinkList начал вести себя должным образом, возвращая правильное количество подключенных устройств.

Заключение:

  • Этот опыт подчеркнул важность тщательного понимания требований внешних библиотек и контекста выполнения при их интеграции в приложения, особенно в нестандартных средах, таких как приложения Electron, взаимодействующие с DLL C++ через FFI.
  • Более того, он подчеркнул проблемы, связанные с «тихими» сбоями, а также необходимость четкой документации и отчетов об ошибках из внешних библиотек, чтобы помочь в отладке и интеграции.

Я также отправил запрос в ST, предложив им предоставить более подробную информацию, а не молча терпеть неудачу, когда в их функциях возникают ошибки.

Я надеюсь, что это обновление прояснит проблему и может помочь другим, сталкивающимся с аналогичными проблемами при взаимодействии FFI в Electron или аналогичных средах.

Другие вопросы по теме