我正在编写一个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文件的话,请将问题保持打开状态。
答案 0 :(得分:11)
函数重载是一种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 :(得分:9)
在代码本身中,使用__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的合法值,或者如果没有或不应该是默认值,则不起作用。
编辑(Adam Haile):更正使用__declspec作为__dllspec不正确所以我可以将其标记为官方答案......它已经足够接近了。
编辑(格雷姆):哎呀 - 谢谢你纠正我的拼写错误!
答案 2 :(得分:8)
我有类似的问题,所以我也希望发布这个问题。
通常使用
extern "C" __declspec(dllexport) void Foo();
导出函数名称很好。 它通常导出名称 没有任何需要,不需要 .def文件。但是,有一些 例如__stdcall函数 和重载的函数名称。
如果声明一个函数来使用 __stdcall约定(就像许多API函数一样)然后
extern "C" __declspec(dllexport) void __stdcall Foo();
将导出一个受损的名称,如 _Foo @ 4。在这种情况下,您可能需要显式映射导出的名称 一个内部错位的名字。
一个。如何导出未编码的名称。在.def文件中添加
----
EXPORTS
; Explicit exports can go here
Foo
-----
这将尝试为内部函数Foo找到“最佳匹配”并将其导出。在上面只有的情况下 一个foo这将创建映射
Foo = _Foo @ 4
可以通过dumpbin / EXPORTS看到
如果您重载了函数名,那么您可能需要在.def文件中明确说出您想要的函数 通过使用entryname [= internalname]语法指定一个受损的名称。 e.g。
----
EXPORTS
; Explicit exports can go here
Foo=_Foo@4
-----
B中。 .def文件的替代方法是,您可以使用#pragma。
“就地”导出名称#pragma comment(linker, "/export:Foo=_Foo@4")
℃。第三种方法是声明只有一个版本的Foo作为extern“C”来导出未解码的。有关详细信息,请参阅here。
答案 3 :(得分:3)
没有正式的方法可以做你想要的,因为dll接口是C api。
编译器本身使用损坏的名称作为变通方法,因此当您不想在代码中进行太多更改时,应使用名称修改。
答案 4 :(得分:2)
没有一种语言或版本无关的导出重载函数的方法,因为修改约定会随着编译器的每个版本而改变。
这就是为什么大多数WinXX功能都有像* Ex或* 2这样有趣的名字的原因之一。
答案 5 :(得分:2)
EXPORTS定义的Systax是:
entryname[=internalname] [@ordinal [NONAME]] [PRIVATE] [DATA]
entryname 是您要导出的函数或变量名称。这是必需的。如果导出的名称与DLL中的名称不同,请在DLL中使用internalname指定导出的名称。
例如,如果您的DLL导出函数func1()并且您希望将其用作func2(),则应指定:
EXPORTS
func2=func1
只需查看损坏的名称(使用Dependency walker)并指定您自己的函数名称。
来源:http://msdn.microsoft.com/en-us/library/hyx1zcd3(v=vs.71).aspx
编辑:这适用于动态DLL,我们需要使用GetProcAddress()来显式获取Dll中的函数。