将一个调用另一个DLL中函数的C++ DLL加载到Matlab中

5
为了学习目的,我正在尝试将一个调用另一个DLL中定义的函数的DLL加载到MATLAB中。我是新手,还没有弄清楚如何做到这一点,也没有找到任何相关资源。
我编写了一个小的C++ 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构建了这个程序,并且通过loadlibrary('example_dll')成功地加载到matlab中。

现在我想要定义这个函数。

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

在另一个 DLL 中(我们称之为 DLL2),并从我的 example_dll 调用该函数,最简单的方法是什么?
我希望能够提供一小段示例代码(最好是用于运行时动态链接,并且不使用模块定义 (.def) 文件),或者提供一个相关资源的链接。谢谢!
简单示例的解决方案:
我认为我已经找到了解决方案。它似乎已经起作用了。
我创建了一个名为 interface_DLL 的 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's 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库例程,而不支持C++类。 我想到的解决方法是使用一个中间DLL作为MATLAB和我想要访问其类的DLL之间的接口。有没有更好的方法?
进一步问题: 有人能解释一下typedef int (__stdcall * pICFUNC)(int);在这里的意义吗? 如果我想要调用example_dll中类的函数,我需要添加什么或者需要做哪些修改?我已经向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
1个回答

2

更进一步的问题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导入它们。然后,只需创建一个实例,通过指针调用其方法,并最终销毁它。 编辑:实现的一些提示
导入创建实例的函数。
FARPROC lpfnCreateInstance = GetProcAddress(HMODULE (hGetProcIDDLL), "createInstance");

声明一个适当的指针类型的函数(返回一个MyClass*,没有参数)

typedef MyClass* (__stdcall * pCREATINST)();

转换 lpfnCreateInstance

pCREATINST createInstance;

createInstance = pCREATINST(lpfnCreateInstance)

创建你的实例。
MyClass *myInstance = creatInstance();

那么您不需要为add函数编写一个包装器,您可以直接从指针调用它。

int res = myInstance->add(123);

对于destroyInstance,您应该做同样的操作,注意类型。请注意,我无法测试此代码,但应该是正确的方法。


感谢您的回答。现在#1已经清楚了。 对于#2,我将您的函数定义添加到了example_dll头文件中(请参见我原始帖子中的EDIT)。我不确定如何在interface_dll中创建实例。如果您能编辑我的interface_dll源文件以展示如何完成这个操作,我将不胜感激。 - Ali Haroon
对于我最终计划实现的项目,我只有头文件和 .lib 文件可用,因此无法在源代码中进行任何更改。我如何从我的中间 DLL 中调用其中包含的类中的函数并将结果返回给 MATLAB? - Ali Haroon
请查看编辑并按照这些建议尝试。至于您的项目,我猜您使用.lib指的是DLL的导入库。不幸的是,我不知道任何一种不使用extern C包装器导入C++代码的方法。 - Marco Guerri
谢谢,这非常有帮助。 对于这个项目,我所说的.lib是指静态库。我有一个包含类和函数的静态库,需要从Matlab中调用。我的做法是编写一个DLL来导入静态库,并编写函数来调用静态库中相应的函数并返回给Matlab。这些函数将被包装在extern C中。 - Ali Haroon

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接