出口能从DLL与dllexport
-
22-08-2019 - |
题
我想一个简单的例的出口的一个函数从C++windows DLL。
我想看到的头,加拿大养恤金计划文件,并def文件(如果绝对必需的)。
我想出名 未装饰.我想使用的大多数标准的呼吁《公约》(__的?).我想用 声明影响(dllexport) 并不需要使用一个清晰的文件。
例如:
//header
extern "C"
{
__declspec(dllexport) int __stdcall foo(long bar);
}
//cpp
int __stdcall foo(long bar)
{
return 0;
}
我试图避免的接头添加了下划线和/或号码(字节计数?) 的名称。
我确定不支持dllimport和dllexport使用同样的标题。我不想要任何信息的出口C++类方法,只要c式的全球职能。
更新
不包括呼吁公约》(和使用外部"C")给我出名字,因为我喜欢,但是这是什么意思?为什么默认的呼吁《公约》,我得到什么pinvoke(.净额),声明(维生素b6),并GetProcAddress会期待什么呢?(我猜GetProcAddress它将取决于功能的指针的呼叫者创建)。
我想这DLL可以使用没有标题的文件,所以我真的不需要很多花哨#定义做的头使用一个来电。
我确定一个答案是,我必须使用一个清晰的文件。
解决方案
如果你想纯C出口,使用C项目不是C ++。 C ++的DLL依靠名称重整为所有C ++主义(命名空间等)。您可以通过进入下C / C ++项目设置编译代码为C - >高级,有其cooresponds编译器开关选项“编译为” / TP和/ TC
。导出/ VC中导入DLL利布斯++
你真正想做的是定义将被包括在所有的源文件在您的DLL项目中的头一个条件宏:
#ifdef LIBRARY_EXPORTS
# define LIBRARY_API __declspec(dllexport)
#else
# define LIBRARY_API __declspec(dllimport)
#endif
然后在要导出您使用LIBRARY_API
功能:
LIBRARY_API int GetCoolInteger();
在您的库构建的项目创建一个定义LIBRARY_EXPORTS
这将导致出口为您的DLL构建的功能。
由于LIBRARY_EXPORTS
不会在项目消耗DLL,当项目包括您的库中的所有的功能的报头文件将被代替进口来限定。
如果你的库是跨平台的,你可以定义LIBRARY_API如无物时不能在Windows上:
#ifdef _WIN32
# ifdef LIBRARY_EXPORTS
# define LIBRARY_API __declspec(dllexport)
# else
# define LIBRARY_API __declspec(dllimport)
# endif
#elif
# define LIBRARY_API
#endif
在使用DLLEXPORT / dllimport的,你不需要使用DEF文件,如果使用DEF文件,你不需要使用DLLEXPORT / dllimport的。这两种方法完成相同的任务不同的方式,相信DLLEXPORT / dllimport的是出两者的推荐方法。
从C导出未重整功能++ DLL用于调用LoadLibrary / PInvoke的
如果您需要此使用LoadLibrary和GetProcAddress的,也许从.NET可以使用extern "C"
在线与您DLLEXPORT做的PInvoke。而且,由于我们使用的,而不是dllimport的GetProcAddress的,我们不需要从上面做ifdef的舞蹈,只是一个简单的DLLEXPORT:
的代码:
#define EXTERN_DLL_EXPORT extern "C" __declspec(dllexport)
EXTERN_DLL_EXPORT int getEngineVersion() {
return 1;
}
EXTERN_DLL_EXPORT void registerPlugin(Kernel &K) {
K.getGraphicsServer().addGraphicsDriver(
auto_ptr<GraphicsServer::GraphicsDriver>(new OpenGLGraphicsDriver())
);
}
和这里的出口会是什么样DUMPBIN /出口:
Dump of file opengl_plugin.dll
File Type: DLL
Section contains the following exports for opengl_plugin.dll
00000000 characteristics
49866068 time date stamp Sun Feb 01 19:54:32 2009
0.00 version
1 ordinal base
2 number of functions
2 number of names
ordinal hint RVA name
1 0 0001110E getEngineVersion = @ILT+265(_getEngineVersion)
2 1 00011028 registerPlugin = @ILT+35(_registerPlugin)
因此,这代码工作正常:
m_hDLL = ::LoadLibrary(T"opengl_plugin.dll");
m_pfnGetEngineVersion = reinterpret_cast<fnGetEngineVersion *>(
::GetProcAddress(m_hDLL, "getEngineVersion")
);
m_pfnRegisterPlugin = reinterpret_cast<fnRegisterPlugin *>(
::GetProcAddress(m_hDLL, "registerPlugin")
);
其他提示
C++:
我只是面临相同的问题,我认为这是值得一提的一个问题是,当一个使用两个 __stdcall
(或 WINAPI
) 和 extern "C"
:
如你所知 extern "C"
除去的装饰,以便代替:
__declspec(dllexport) int Test(void) --> dumpbin : ?Test@@YaHXZ
你获得一个符号的名字未修饰:
extern "C" __declspec(dllexport) int Test(void) --> dumpbin : Test
但是的 _stdcall
(=宏WINAPI,改变调《公约》)也装饰的名字所以,如果我们使用我们获得:
extern "C" __declspec(dllexport) int WINAPI Test(void) --> dumpbin : _Test@0
和好处的 extern "C"
是因为失去的符号是装饰(与_@字节)
注意这个 只 发生x86结构,因为 的
__stdcall
《公约》被忽略,在64(msdn : 在64架构,通过《公约》的论点是通过注册可能时,以及随后的参数是通过对栈.).
这是特别棘手的如果你的目标x86和64平台。
两个解决方案
使用定义的文件。但是,这迫使你保持国家的清文件。
最简单的方式:定义的宏(见 msdn) :
#define出的评论(接头,"/出口:"__功能__"=" __FUNCDNAME__)
然后包括以下说明在功能机构:
#pragma EXPORT
充满例子:
int WINAPI Test(void)
{
#pragma EXPORT
return 1;
}
这将出口的功能未装饰用于x86和64目标,同时保留 __stdcall
《公约》x86。的 __declspec(dllexport)
是不是 需要在这种情况。
我完全相同的问题,我的溶液使用定义模块文件(.def),而不是的 __declspec(dllexport)
定义出口(http://msdn.microsoft.com/en-us/library/d91k01sh.aspx).我不知道为什么这一工作,但它不会
我觉得_naked可能会得到你想要的东西,但它也可以防止编译器生成的函数堆栈管理代码。为extern“C”导致空调风格名称修饰。删除这应该摆脱你_的的。链接器不会添加下划线,编译器。 STDCALL导致要附加参数堆栈大小。
有关详情,请参见: http://en.wikipedia.org/wiki/X86_calling_conventions http://www.codeproject.com/KB/cpp/calling_conventions_demystified.aspx
在更大的问题是,为什么你要这么做?有什么不对的错位的名字呢?