在 C++ DLL 中的 C 样式导出 API 之间使用公共 class 的方法

Way to use common class between C style exporting API in C++ DLL

我正在编写 C++ 库,现在正在为其设计 C 风格 API。现在我有一堆使用 main class 单例的方法,这里简化了声明:

extern "C" {
    MYDLL_API void getAudioDeviceList();
    MYDLL_API void getWindowList();

    MYDLL_API uint32_t BeginVideoCapture();
    MYDLL_API uint32_t StopVideoCapture();
}

但到目前为止我决定删除单例,出现了两难选择。通过 API 调用使用我的 class 最优雅的方法是什么?现在我只看到一种方法,使用全局变量和 init 方法,比如(其中 CVideoConverter 是 C struct wrap under C++ class):

extern "C" {
    CVideoConverter* t = new CVideoConverter();

    MYDLL_API void getAudioDeviceList();
    MYDLL_API void getWindowList();

    MYDLL_API uint32_t BeginVideoCapture();
    MYDLL_API uint32_t StopVideoCapture();
}

或者我应该创建一些 C 结构,它包含所有 API 方法和指向 CVideoConverter 对象的指针,导出结构本身。等待您的建议,谢谢!

一个好的方法(不是唯一的方法)是为您的 class CVideoConverter 提供实例工厂函数,它将 return 通过 reinterpret_cast 转换的 C 实例].这样,您可以通过提供此实例引用作为第一个参数来调用 C 导出的函数。在 DLL 端,您重新转换为 C++ 实例并调用实例的方法。

请关注此 link,其中提供了更详细的解释和非常好的示例。

C++ DLL to be used in C program

在头文件中定义全局变量永远不会带来幸福。相反,如果您想要 C++ 代码的 C API,我建议您实际查看 FILE 和标准 C 文件处理函数。

FILEtype-alias是一个不透明的结构,你不知道它的内容,也不应该关心。相反,你有一个函数分配你的不透明结构的实例和 returns 一个指向它的指针。然后你所有的 C API 函数都将这个指针作为参数。

这个不透明的结构到底是什么?这并不重要,它可以只是一个私有结构,其中包含您的 main class 的一个实例。然后具有完整结构定义的 C API 函数和 classes) 可以使用它来调用所需的成员函数。


一个简单的小例子:

public头文件,这是C应用程序应该包含的:

#ifndef MY_C_API_H
#define MY_C_API_H

#ifdef __cplusplus
extern "C" {
#endif

// Forward declaration of the MYSTRUCT structure, and definition of type-alias
typedef struct MYSTRUCT MYSTRUCT;

MYSTRUCT *my_create(void);
void my_destroy(MYSTRUCT *mystruct);
void my_do_something(MYSTRUCT *mystruct, int some_argument);

#ifdef __cplusplus
}
#endif

#endif // End of header include guard

private 头文件,仅供您的应用程序内部使用:

#ifndef MY_PRIVATE_H
#define MY_PRIVATE_H

#include "my_c_api.h"
#include "my_class.h"

struct MYSTRUCT
{
    MyClass my_object;
};

#endif

C的执行API:

#include "my_private.h"

extern "C"
{
    MYSTRUCT *my_create(void)
    {
        return new MYSTRUCT;
    }

    void my_destroy(MYSTRUCT *mystruct)
    {
        delete mystruct;
    }

    void my_do_something(MYSTRUCT *mystruct, int some_argument)
    {
        mystruct->my_object.do_something(some_argument);
    }
}