我正在编写一个 C/C++ DLL,并且想要导出我在使用像这样的 .def 文件之前完成的某些函数

LIBRARY "MyLib"
EXPORTS
  Foo
  Bar

代码定义如下,例如:

int Foo(int a);
void Bar(int foo);

但是,如果我想声明 Foo() 的重载方法,例如:

int Foo(int a, int b);

由于 def 文件只有函数名称,没有完整的原型,我看不到它将如何处理重载函数。您是否只使用一个条目,然后在将正确的原型函数指针传递给 LoadLibrary() 时指定您想要的重载版本?

编辑:需要明确的是,这是在 Windows 上使用 Visual Studio 2005

编辑:将非 def (__declspec) 方法标记为答案...我知道这实际上并没有像我想要的那样使用 def 文件解决问题,但似乎可能没有使用 def 文件的(官方)解决方案。但是,如果有人知道我们没有重载函数和 def 文件,我们将保留这个问题。

有帮助吗?

解决方案

在代码本身中,使用 __declspec(dllexport) 标记要导出的函数。例如:

#define DllExport __declspec(dllexport)

int DllExport  Foo( int a ) {
  // implementation
}
int DllExport Foo( int a, int b ) {
  // implementation
}

如果这样做,则无需在 .def 文件中列出函数。

或者,您可以使用默认参数值,例如:

int Foo( int a, int b = -1 )

这假设 b 存在一个值,您可以使用该值来指示它未使用。如果 -1 是 b 的合法值,或者没有或不应该有默认值,则这将不起作用。

编辑(亚当·海尔):更正为使用 __declspec 因为 __dllspec 不正确,所以我可以将其标记为官方答案......它足够接近。

编辑(格雷姆):哎呀 - 感谢您纠正我的错字!

其他提示

函数重载是一项 C++ 功能,它依赖于名称修饰(链接器错误消息中的神秘函数名称)。

通过将损坏的名称写入 def 文件,我可以链接并运行我的测试项目:

LIBRARY "TestDLL"
EXPORTS
    ?Foo@@YAXH@Z
    ?Foo@@YAXHH@Z

似乎适用于

void Foo( int x );
void Foo( int x, int y );

因此,从错误消息中复制 C++ 函数名称并将它们写入 def 文件中。然而,真正的问题是:为什么要使用 def 文件而不是使用 __declspec(dllexport) ?

损坏的名称是不可移植的,我用 VC++ 2008 进行了测试。

我也有类似的问题,所以我也想就此发表文章。

  1. 通常使用

    extern "C" __declspec(dllexport) void Foo();
    

    导出函数名称就可以了。它会 通常 导出不受欢迎的名称而无需.DEF文件。但是,有一些例外,例如__ -stdcall函数和过载函数名称。

  2. 如果您声明一个函数以使用__stdcall judent(如许多API函数所做的那样),则

    extern "C" __declspec(dllexport) void __stdcall Foo();
    

    将导出一个像_foo@4这样的杂乱名称。在这种情况下,您可能需要将导出的名称明确映射到内部杂乱的名称。

A。如何导出未损坏的名称。在 .def 文件中添加

----
EXPORTS
    ; Explicit exports can go here

    Foo
-----

这将尝试为内部函数 Foo 找到“最佳匹配”并将其导出。在上面只有一个foo的情况下,这将创建映射

富 = _Foo@4

通过 dumpbin /EXPORTS 可以看到

如果您已超载一个函数名称,则可能需要通过使用entryName [= noternalname]语法指定一个杂乱的名称,在.def文件中明确说明所需的函数。例如

----
EXPORTS
    ; Explicit exports can go here

    Foo=_Foo@4
-----

B..def 文件的替代方法是您可以使用 #pragma “就地”导出名称。

#pragma comment(linker, "/export:Foo=_Foo@4")

C。第三种替代方法是仅将 Foo 的一个版本声明为 extern "C" 以完整导出。看 这里 了解详情。

没有官方的方法可以做你想做的事情,因为 dll 接口是 C api。

编译器本身使用重整名称作为解决方法,因此当您不想在代码中进行太多更改时,应该使用名称重整。

没有一种与语言或版本无关的方法来导出重载函数,因为重整约定可能会随着编译器的每个版本而变化。

这就是为什么大多数 WinXX 函数都有*Ex 或 *2 等有趣名称的原因之一。

EXPORTS 定义的系统是:

entryname[=internalname] [@ordinal [NONAME]] [PRIVATE] [DATA]

条目名称 是要导出的函数或变量名称。这是必需的。如果导出的名称与DLL中的名称不同,请使用internalname指定DLL中导出的名称。

例如,如果您的 DLL 导出函数 func1() 并且您希望将其用作 func2(),则可以指定:

EXPORTS
func2=func1

只需查看损坏的名称(使用依赖项遍历器)并指定您自己的函数名称即可。

来源: http://msdn.microsoft.com/en-us/library/hyx1zcd3(v=vs.71).aspx

编辑:这适用于动态 DLL,我们需要使用 GetProcAddress() 显式获取 Dll 中的函数。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top