我正在编写一个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()时指定您想要的重载版本?
编辑:要清楚,这是在使用Visual Studio 2005的Windows上
编辑:将非def(__ declspec)方法标记为答案...我知道这实际上并没有像我想的那样使用def文件解决问题,但似乎很可能没有使用def文件的(官方)解决方案.但是,如果有人知道我们没有重载函数和def文件,我们会将问题保持打开状态.
函数重载是一种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进行了测试.
在代码本身中,使用__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不正确所以我可以将其标记为正式答案......它足够接近.
编辑(格雷姆):哎呀 - 感谢纠正我的错字!
我有一个类似的问题,所以我也想发布这个问题.
通常使用
extern "C" __declspec(dllexport) void Foo();
导出函数名称很好.它通常会输出名称unmangled而不需要.def文件.但是,有一些例外,例如__stdcall函数和重载函数名.
如果声明一个函数使用__stdcall约定(就像许多API函数一样)那么
extern "C" __declspec(dllexport) void __stdcall Foo();
将导出像_Foo @ 4这样的错位名称.在这种情况下,您可能需要将导出的名称显式映射到内部损坏的名称.
A.如何导出未编码的名称.在.def文件中添加
---- EXPORTS ; Explicit exports can go here Foo -----
这将尝试为内部函数Foo找到"最佳匹配"并将其导出.在上面只有一个foo的情况下,这将创建映射
Foo = _Foo @ 4
通过dumpbin/EXPORTS可以看到
如果您重载了一个函数名,那么您可能需要通过使用entryname [= internalname]语法指定一个受损的名称来明确说明.def文件中您想要的函数.例如
---- EXPORTS ; Explicit exports can go here Foo=_Foo@4 -----
B. .ff文件的替代方法是您可以使用#pragma"就地"导出名称.
#pragma comment(linker, "/export:Foo=_Foo@4")
C.第三种方法是将一个版本的Foo声明为extern"C",以便解除输出.详情请见此处.