C ++中的非托管DLL

时间:2008-10-25 07:04:22

标签: c++ dll unmanaged

我一直在阅读很多关于C ++中非托管DLL的教程/文章。然而,对于我的生活,我似乎无法掌握这个概念。关于它是否需要头文件,如何导出它,是否需要.lib文件以及你有什么,我很容易感到困惑。

所以,我们假设我只有这样的函数:

public int calculateSquare(int num)
{
    return num*num;
}

忽略实际的代码,我需要做什么才能将这个简单的函数本身变成一个我可以调用的DLL?我只是添加__dllexport或其他任何内容到第一行还是我需要标题?我为这一切感到困惑。

4 个答案:

答案 0 :(得分:15)

我不能强调这一点,C ++编译器没有看到头文件,在预处理器完成后,只有一个大的源文件(也称为编译单元)。因此严格来说,您不需要标头来从dll导出此函数。 您需要的是某种形式的条件编译,以便在您正在编译的dll中导出函数并将其导入客户端代码中。

通常,这是通过宏和头文件的组合来完成的。您创建一个名为MYIMPORTEXPORT的宏,并通过使用宏条件语句使其在dll中与__declspec(dllexport)一样工作,在客户端代码中使用__declspec(dllimport)。

在文件MYIMPORTEXPORT.h中

#ifdef SOME_CONDITION
#define MYIMPORTEXPORT __declspec( dllexport )
#else
#define MYIMPORTEXPORT __declspec( dllimport )
#endif
文件MyHeader.h中的

#include <MyImportExport.h>

MYIMPORTEXPORT public int calculateSquare(int num)
{
    return num*num;
}

在dll .cpp文件中

#define SOME_CONDITION

#include <MyHeader.h>
客户端代码.cpp文件中的

#include <MyHeader.h>

当然,您还需要向链接器发出信号,表明您正在使用/DLL option构建一个dll。

构建过程也将生成一个.lib文件,这是一个静态库 - 在这种情况下称为存根 - 客户端代码需要链接到它,就像链接到真正的静态库一样。自动地,将在运行客户端代码时加载dll。当然,操作系统需要通过其查找机制找到dll,这意味着你不能将dll放在任何地方,而是放在特定的位置。 Here就更多了。

一个非常方便的工具,用于查看是否从dll导出了正确的函数,以及客户端代码是否正确导入dumpbin。分别用/ EXPORTS和/ IMPORTS运行它。

答案 1 :(得分:6)

QBziZ的答案是对的。见Unmanaged DLLs in C++

要完成它:在C ++中,如果需要使用符号,则必须告诉编译器它是否存在,并且通常是它的原型

在其他语言中,编译器将自己探索库,并找到符号etvoilà

在C ++中,您必须告诉编译器。

将C / C ++标题视为书目目录

最好的方法是在一些常见的地方放置所需的代码。 “界面”,如果你愿意的话。这通常在头文件中完成,称为头文件,因为这通常不是一个独立的源文件。标题只是一个文件,其目的是包含(即由预处理器复制/粘贴)到真正的源文件中。

实质上,你似乎必须声明两次符号(函数,类,等等)。与其他语言相比,这几乎是一种异端。

您应该将其视为一本书,包含摘要表或索引。在表格中,您有所有章节。在文中,您有章节及其内容。

有时,你很高兴你有章节清单。

在C ++中,这是标题。

DLL怎么样?

所以,回到DLL问题:DLL的目的是导出代码将使用的符号。

因此,以C ++方式,您必须在编译时导出代码(例如,在Windows中,使用__declspec,例如)和“发布”导出内容的表(即包含“公共”标题的表)出口声明)。

答案 2 :(得分:1)

导出功能的核对表:

  • 调用约定适合调用者吗? (这决定了参数和结果的传递方式,以及谁负责清理堆栈)。你应该明确说出你的召集惯例。
  • 符号将以哪个名称导出? C ++通常需要修饰(“mangle”)符号的名称,例如区分不同的重载。
  • 告诉链接器将该函数显示为DLL Export

在MSVC上:

  • __stdcall(这是pascal调用约定)是导出符号的典型调用约定 - 我猜是大多数客户都支持。
  • extern“C”允许您导出符号C风格而不需要名称修改
  • 使用__declspec(dllexport)标记要导出的符号,或链接单独的.def文件,其中列出要导出的符号。使用.def文件,您也可以仅按顺序导出(而不是按名称),并更改导出的符号的名称。

答案 3 :(得分:0)

您需要使用__declspec( dllexport )导出函数或将函数添加到模块定义文件(.def)。然后将该项目编译为DLL。

在客户端,您有两种选择。使用编译DLL时生成的导入库(.lib)。只需使用此库链接您的客户端项目,即可访问从DLL导出的函数。而且你需要一个头文件,因为编译器需要知道你的函数的签名 - 它返回int并获取一个int。回顾一下,您需要链接一个导入库(.lib)和一个包含函数头的头文件。

另一种方法是使用WinAPI调用LoadLibrary然后GetProcAddress动态加载DLL以获取指向该函数的指针。指向函数的指针必须具有正确的类型,以便编译器可以为其提供正确的参数,并使用正确的调用约定。