searchusermenu
  • 发布文章
  • 消息中心
点赞
收藏
评论
分享
原创

DLL 导出符号的两种方式

2023-07-20 07:33:54
16
0

最近恰好需要用 C++ 实现一个供 C# .NET 调用的模块,用dllexport导出符号的时候出现了一点问题,明明已经看到了导出符号,但是 .NET 在调用的时候,就是找不到方法。然后用 def 文件的方式导出符号就正常,突然对这两种方式的区别产生兴趣,之前一直没有研究过,就仔细了查阅一番。

以导出名为 TESTFUNC 方法为例:

def 文件方式

,正常在程序中定义方法,然后新建一个 .def 文件,内容类似

LIBRARY
EXPORT
    TESTFUNC

在其他工程使用这个方法的时候需要头文件,然后在连接时指定 .def 文件目录。

dllexport方式

在定义 TESTFUNC 方法时,在声明前加上 __declspec(dllexport)

区别

这里就不得不说导出符号在 DLL 中的形式。实际上对于 C++ 来说,当导出的时候,不会以原名导出,因为会加上一些符号字母后缀,实际上如果了解 C++ 的人,也会知道 C++ 在处理函数重载的时候,其实也用了这个套路,实际上编译之后就没有重载的概念了,而是根据参数生成了独一无二的方法名。

那说回来既然名字不同,那为什么其他模块调用还没问题呢。回答这个问题之前要先知道其他模块如何引用。

调用导出函数的方式

一般有三种形式:

  • .h 提供声明之后,直接调用,在连接的时候指定 .def 文件目录;
  • .h 提供声明之后,直接调用,链接的时候指定 .lib 文件地址
  • 内部声明要调用函数的函数指针,loadlibrary 之后,直接取到函数地址,调用函数;

了解了这三种方式之后,就可以回答上边的问题。

  • 对于1、2两种方式,由编译器自动转换函数名,寻找到正确的地址,链接之;
  • 对于第3种方式,如果不把真正的函数方法名写对,就找不到函数了。

所以其他模块调用没问题。

话说回来,那也不可能每次都把@那些符号写对。所以会看到有时候导出的时候_extern "C" _declspec(dllexport)这样写,这是为了让函数以 C 的方式来编译,这样导出的方法就是没有那些符号的了,但这样有个问题,就是函数必须以 C 方式调用,而且也不能用来导出类对象,原因是显而易见的……

其实当了解上边之后,不难发现,1、2才是我们最想要的,3就很局限。这样问题就来了,1、2两种方式又有什么区别呢:

区别就在这个 .lib 上,如果在 C++ 或者 C 工程这个范围来说,确实没区别。但是假如调用工程不是 C++ 工程呢,他就是个 C# 工程呢,他是没办法用 .lib 的。

综上所述:.def 文件的方式才是最通用的做法。那回到我最初的问题,我的 C# 工程之所以在调用使用 dllexport导出的方法失败,就是因为,我没有写对真正的方法名(带一堆符号的那个)。而使用 .def 文件的话,就没有这个问题了。

0条评论
0 / 1000
Harper
17文章数
0粉丝数
Harper
17 文章 | 0 粉丝
原创

DLL 导出符号的两种方式

2023-07-20 07:33:54
16
0

最近恰好需要用 C++ 实现一个供 C# .NET 调用的模块,用dllexport导出符号的时候出现了一点问题,明明已经看到了导出符号,但是 .NET 在调用的时候,就是找不到方法。然后用 def 文件的方式导出符号就正常,突然对这两种方式的区别产生兴趣,之前一直没有研究过,就仔细了查阅一番。

以导出名为 TESTFUNC 方法为例:

def 文件方式

,正常在程序中定义方法,然后新建一个 .def 文件,内容类似

LIBRARY
EXPORT
    TESTFUNC

在其他工程使用这个方法的时候需要头文件,然后在连接时指定 .def 文件目录。

dllexport方式

在定义 TESTFUNC 方法时,在声明前加上 __declspec(dllexport)

区别

这里就不得不说导出符号在 DLL 中的形式。实际上对于 C++ 来说,当导出的时候,不会以原名导出,因为会加上一些符号字母后缀,实际上如果了解 C++ 的人,也会知道 C++ 在处理函数重载的时候,其实也用了这个套路,实际上编译之后就没有重载的概念了,而是根据参数生成了独一无二的方法名。

那说回来既然名字不同,那为什么其他模块调用还没问题呢。回答这个问题之前要先知道其他模块如何引用。

调用导出函数的方式

一般有三种形式:

  • .h 提供声明之后,直接调用,在连接的时候指定 .def 文件目录;
  • .h 提供声明之后,直接调用,链接的时候指定 .lib 文件地址
  • 内部声明要调用函数的函数指针,loadlibrary 之后,直接取到函数地址,调用函数;

了解了这三种方式之后,就可以回答上边的问题。

  • 对于1、2两种方式,由编译器自动转换函数名,寻找到正确的地址,链接之;
  • 对于第3种方式,如果不把真正的函数方法名写对,就找不到函数了。

所以其他模块调用没问题。

话说回来,那也不可能每次都把@那些符号写对。所以会看到有时候导出的时候_extern "C" _declspec(dllexport)这样写,这是为了让函数以 C 的方式来编译,这样导出的方法就是没有那些符号的了,但这样有个问题,就是函数必须以 C 方式调用,而且也不能用来导出类对象,原因是显而易见的……

其实当了解上边之后,不难发现,1、2才是我们最想要的,3就很局限。这样问题就来了,1、2两种方式又有什么区别呢:

区别就在这个 .lib 上,如果在 C++ 或者 C 工程这个范围来说,确实没区别。但是假如调用工程不是 C++ 工程呢,他就是个 C# 工程呢,他是没办法用 .lib 的。

综上所述:.def 文件的方式才是最通用的做法。那回到我最初的问题,我的 C# 工程之所以在调用使用 dllexport导出的方法失败,就是因为,我没有写对真正的方法名(带一堆符号的那个)。而使用 .def 文件的话,就没有这个问题了。

文章来自个人专栏
Windows 编程
9 文章 | 1 订阅
0条评论
0 / 1000
请输入你的评论
0
0