Загрузите С++ DLL в matlab, который вызывает функции в другой DLL

108
11

В целях обучения я пытаюсь загрузить DLL в MATLAB, который вызывает функции, определенные в другой DLL. Я новичок во всем этом, и еще не смог понять, как я буду заниматься этим, и мне не удалось найти какие-либо релевантные ресурсы.


Я написал небольшую DLL в С++, которая выглядит примерно так:


//example_dll.h
#ifndef EXAMPLE_DLL_H
#define EXAMPLE_DLL_H

#ifdef __cplusplus
extern "C" {
#endif

#ifdef BUILDING_EXAMPLE_DLL
#define EXAMPLE_DLL __declspec(dllexport)
#else
#define EXAMPLE_DLL __declspec(dllimport)
#endif

int EXAMPLE_DLL Double(int x);

#ifdef __cplusplus
}
#endif

#endif // EXAMPLE_DLL_H


и исходный файл:


//example_dll.cpp
#include <stdio.h>
#include "example_dll.h"

int Double(int x)
{
return 2 * x;
}


Это я создал с помощью MinGW w64 и без проблем загружался в matlab с помощью loadlibrary('example_dll').


Теперь я хочу определить функцию


int Double(int x)
{
return 2 * x;
}

В другой DLL (позвольте ей назвать DLL2) и вызвать эту функцию из моего example_dll.
Каким будет самый простой способ сделать это?


Я был бы признателен за короткий примерный код (желательно для динамической компоновки во время выполнения и без использования файлов определения модуля (.def)) или ссылку на соответствующий ресурс в сетях.
Спасибо!


РЕШЕНИЕ ДЛЯ ПРОСТОГО ПРИМЕРА:

Я думаю, что получил решение. Кажется, что он работает.


Я создал DLL с именем interface_DLL, который я загрузил в MATLAB, и из которого я назвал свою функцию в example_dll


вот он:


//interface_dll.h
#ifndef INTERFACE_DLL_H
#define INTERFACE_DLL_H

#ifdef __cplusplus
extern "C" {
#endif

#ifdef BUILDING_INTERFACE_DLL
#define INTERFACE_DLL __declspec(dllexport)
#else
#define INTERFACE_DLL __declspec(dllimport)
#endif

int INTERFACE_DLL Quadruple(int x);

#ifdef __cplusplus
}
#endif

#endif // INTERFACE_DLL_H


и исходный файл:


//interface_dll.cpp
#include <windows.h>
#include <stdio.h>
#include "interface_dll.h"
#include "example_dll.h"

int Quadruple(int x)
{
/* get handle to dll */
HINSTANCE hGetProcIDDLL = LoadLibrary("C:\\Users\\uidr0605\\Documents\\ExampleDLL\\example_dll.dll");

/* get pointer to the function in the dll*/
FARPROC lpfnGetProcessID = GetProcAddress(HMODULE (hGetProcIDDLL),"Double");

/*
Define the Function in the DLL for reuse. This is just prototyping the dll function.
A mock of it. Use "stdcall" for maximum compatibility.
*/
typedef int (__stdcall * pICFUNC)(int);

pICFUNC Double;
Double = pICFUNC(lpfnGetProcessID);

/* The actual call to the function contained in the dll */
int intMyReturnVal = Double(x);
intMyReturnVal = Double(intMyReturnVal);

/* Release the Dll */
FreeLibrary(hGetProcIDDLL);

/* The return val from the dll */
return intMyReturnVal;
}


Я загружаю его из MATLAB следующим образом:


%loadDLL.m
path = 'C:\Path\to\DLL\';
addpath(path);
loadlibrary('interface_dll')
i = 2;
x = calllib('interface_dll', 'Quadruple', i)

Причина, по которой я переживаю этот процесс, заключается в том, что интерфейс общей библиотеки MATLAB поддерживает только библиотечные подпрограммы C, а не классы С++.


Моя идея обходного пути заключается в использовании промежуточной DLL для работы в качестве интерфейса между MATLAB и DLL, к которым я собираюсь получить доступ.
Есть ли лучший способ сделать это?


ДАЛЬНЕЙШИЕ ВОПРОСЫ:


Может ли кто-нибудь объяснить значение строки typedef int (__stdcall * pICFUNC)(int);, как это применимо здесь?
Что мне нужно добавить или какие изменения я должен был бы сделать, если бы я хотел вызвать функцию в классе в example_dll?


EDIT: я добавил следующий код в заголовочный файл example_dll:


class EXAMPLE_DLL MyClass
{
public:
int add2(int);
};

#ifdef __cplusplus
extern "C" {
#endif

MyClass EXAMPLE_DLL *createInstance(){
return new MyClass();
}

void EXAMPLE_DLL destroyInstance(MyClass *ptrMyClass){
delete ptrMyClass;
}

#ifdef __cplusplus
}
#endif

спросил(а) 2021-01-25T17:02:36+03:00 4 месяца, 3 недели назад
1
Решение
78

Дальнейший вопрос 1


Следующее определение


typedef int (__stdcall * pICFUNC)(int);

определяет новый тип pICFUNC, который является указателем на функцию, которая принимает int и возвращает int. Кроме того, функция должна вызываться в соответствии с соглашением о вызове __stdcall, которое указывает, как должны передаваться аргументы и как получить возвращаемое значение.
Эта ссылка объясняет typedef с указателями функций. См. Также следующий раздел: Использование typedef с типом приведения, так как в строке


Double = pICFUNC(lpfnGetProcessID);

Вместо этого используется pICFUNC.


Дальнейший вопрос 2


Ниже приводится очень простой пример, чтобы дать идею. Если у вас есть класс в example_dll с именем MyClass, у которого есть метод


int add(int num);

вы можете реализовать следующие функции:


MyClass *createInstance(){
return new MyClass();
}

void destroyInstance(MyClass *ptrMyClass){
delete ptrMyClass;
}


Эти функции должны быть extern "C", и вы можете импортировать их с помощью GetProcAddress. Тогда было бы просто создать экземпляр, вызвав его методы с помощью указателя и в конечном итоге уничтожив его.

EDIT: Некоторые подсказки для реализации


Импортировать функцию для создания экземпляра


FARPROC lpfnCreateInstance = GetProcAddress(HMODULE (hGetProcIDDLL), "createInstance");

Объявить правильный тип указателя для функции (возвращает MyClass *, без аргументов)


typedef MyClass* (__stdcall * pCREATINST)();

Листинг lpfnCreateInstance


pCREATINST createInstance;

createInstance = pCREATINST(lpfnCreateInstance)


Создайте свой экземпляр


MyClass *myInstance = creatInstance();

Тогда вам не нужна оболочка для добавления, вы можете просто вызвать ее из вашего указателя.


int res = myInstance->add(123);

Вы должны сделать то же самое для destroyInstance, будучи осторожным с типами
Обратите внимание, что я не могу проверить этот код, но это должен быть правильный подход.

ответил(а) 2021-01-25T17:02:36+03:00 4 месяца, 3 недели назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема