【问题标题】:How to export/import a C struct from a DLL/ to a console application using __declspec( dllexport/import )如何使用 __declspec( dllexport/import ) 将 C 结构从 DLL/ 导出/导入到控制台应用程序
【发布时间】:2013-03-11 15:15:25
【问题描述】:

这是我第一次处理 DLL。根据 MSDN 文档,我创建了一个头文件 fooExports.h,其中包含根据预处理器定义定义的宏:

#ifdef FOODLL_EXPORTS
    #define FOO_API __declspec( dllexport )
#else
    #define FOO_API __declspec( dllimport )

我的意图是在我的 DLL 实现和控制台应用程序中都使用这个头文件。到目前为止,导入和导出功能工作得很好。当我尝试导出一个已定义的结构时,问题就出现了,我需要该结构作为其中一个导出函数的参数。例如,在前面提到的头文件中我声明了FOO_API void foo( FooParams *args )args是一个结构体,定义如下:

typedef struct FooParams
{
    char *a;
    char *b;
    void *whatever; //some other type
} FooParams;

这个结构必须在 foo.h 而不是 fooExports.h 中定义。有没有办法导出这个结构而不把它从它的原始头文件中取出(考虑到我想把导出/导入集中在 fooExports.h 中)。 有什么更好的方法来做到这一点? DLL 都是 C 以及使用它的客户端应用程序。

【问题讨论】:

  • 您不导出类型,而是导出链接器符号。
  • @aschepler 你介意扩展一下吗?
  • 完全不清楚你为什么使用两个 .h 文件,或者为什么你没有为 foo() 声明参数类型。结构中没有可导出的内容,它没有任何代码。避免这种困境的简单方法是只使用一个 .h 文件并完成它。
  • @HansPassant 我按照您的建议修复了参数的类型。我不想要一个头文件的原因是因为导出头文件将与客户端和 DLL 共享,我不想在该头文件中公开我所有结构的声明。跨度>
  • 您希望客户端代码看到 __declspec(dllimport) FooParams。因此,到目前为止您发布的所有内容都属于一个 .h 文件。如果您有其他特定于实现的 .h 文件,那么只需将它们#include 到您的 .cpp 文件中。

标签: c dll struct dllimport dllexport


【解决方案1】:

如果客户端对FooParams 的唯一用途是获取从 DLL 函数返回的指向它的指针并将这些指针传递给其他 DLL 函数,则可以将其设为“不透明类型”:Put

typedef struct FooParams FooParams;

在 fooExports.h 中。 FOO_API 宏不属于该声明。 opaque 类型意味着客户端代码不能:

  • 创建FooParams 类型的任何变量(但FooParams * ptr = NULL; 可以)。
  • FooParams 的任何成员一起做任何事情。
  • 找到sizeof(FooParams) - 因此无法正确地为一个或多个FooParams 对象提供malloc 空间。

你也不能#define 对执行上述任何操作的客户端可见的宏。所以你的 DLL 需要有一个或多个“构造函数”或“工厂”函数,可能类似于

FOO_API FooParams* CreateFooParams(const char * input);

定义一个匹配的“析构函数”也是一个好习惯,比如

FOO_API void DestroyFooParams(FooParams * p);

即使定义就像 { free(p); } 一样简单,因为如果在 DLL 内分配的内存被外部代码释放,有时可能会出现问题,反之亦然(因为并非所有 Windows 代码都使用mallocfree 的定义相同。

如果这一切都太极端了,唯一的其他选择是将 #includestruct 定义放在导出的头文件中,并使其对客户端可见。没有它,除了传递指针之外,任何对FooParams 做某事的尝试都是不可能的,因为编译器不会知道FooParams 中的内容。编译器(与链接器相反)仅从命令行参数和#include-d 文件中获取信息,而不是从库或 DLL 中获取信息。

【讨论】:

  • 非常感谢。这是一个很好的答案!在等待响应时,我直观地采用了including 我的标头与客户端中的结构定义的方法。只是想确定没有其他办法。正如你刚才解释的那样,我不需要做什么。再次感谢您的宝贵时间!
猜你喜欢
  • 1970-01-01
  • 2012-04-14
  • 1970-01-01
  • 2011-03-28
  • 1970-01-01
  • 2021-09-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多