C++DLL出口:装饰/损坏的名字
-
25-09-2019 - |
题
创建基本的C++DLL和出口的名称使用定义模块文件(MyDLL.def).编译之后我检查了出口功能名称的使用 dumpbin.exe
我希望看到:
SomeFunction
但我看到这个:
SomeFunction = SomeFunction@@@23mangledstuff#@@@@
为什么?
出口的功能会出现未修饰(尤其是相对于不使用模块Def文件),但为什么其他的东西?
如果我用 dumpbin.exe
对DLL从任何商业应用程序,你获得清洁:
SomeFunction
并没有别的...
我也试着去除模块的定义和出口的名称中使用"C"的风格的出口,即:
extern "C" void __declspec(dllexport) SomeFunction();
(简单地使用"外部"C"没有创造一个出口功能)
然而,这仍然造成相同的输出,即:
SomeFunction = SomeFunction@@@23mangledstuff#@@@@
我也试过 #define dllexport __declspec(dllexport)
选项并创建了一个LIB没有问题。然而,我不想要必须提供一个LIB文件的人使用DLL在他们C#应用程序。
这是一个普通的香草C++DLL(管理的代码),编制用C++不过是一个简单的标题和编码。没有模块Def我错位的出口功能(我可以创建一个静态的图书馆和使用LIB没有问题。我试着避免那)。如果我用 extern "C" __declspec(dllexport)
或 模块的定义,我得到了什么似乎是一个未装饰功能的名字...唯一的问题是,它是随后通过一个"="和什么看起来像一个装饰版本的功能。我想要摆脱的东西之后的"="-或至少理解为什么它是存在的。
因为它的立场,我敢肯定,我可以打电话的功能,从C#用P/援引...我只是想避免这种垃圾在结束"=".
我很开放的建议如何改变该项目的/编译器的设置,但是,我只是用标准Visual Studio DLL模板-没有什么特别的。
解决方案
你可以得到你想要什么通过关闭"调试"的信息的产生。项目+性、连接器,调试,产生"调试"的信息=没有。
当然,你只想要这样做对于释放建设。那里的选择是已经设置这种方式。
其他提示
而不是使用。def文件只是插入 pragma comment
像这样的
#pragma comment(linker, "/EXPORT:SomeFunction=_SomeFunction@@@23mangledstuff#@@@@")
编辑:或甚至更加容易:身体内部的功能使用
#pragma comment(linker, "/EXPORT:"__FUNCTION__"="__FUNCDNAME__)
...如果你有麻烦找到装饰职能名称。这最后一批注可以进一步减少用一个简单的宏观定义。
你必须要声明的功能 extern "C"
如果你不想要他们的名字被损坏。
从经验看,要小心,如果您使用 __stdcall
在您的签名。与 __stdcall
, ,名称仍将是错位的某种程度上(你将迅速找出足够的).显然,有两个级别的重整,其中一个 extern "C"
交易与至C++的水平,但它不处理与另一个级别的名称重整造成的 __stdcall
.额外重整显然是有关超载的--但我并不肯定这一点。
对不起,对于在回答一个旧线,但是已被标记为答案并没有为我工作。
作为一个人数有所指出的,外部的"C"装饰是很重要的。改变"项目的/特性/连接/调试"/"产生"调试"的信息"的设定作出绝对没有任何差错位的名称正在产生的对我来说在"调试"或释放建设模式。
设置:VS2005编制一些用C++类库项目。我检查汇编。dll输出与微软的依赖Walker工具。
这里是一个例子配方,为我工作...
在项目。h:
#define DllExport extern "C" __declspec( dllexport )
DllExport bool API_Init();
DllExport bool API_Shutdown();
在project.cpp:
#include "project.h"
bool API_Init()
{
return true;
}
bool API_Shutdown()
{
return true;
}
然后被称为从C#管理的代码、类。cs:
using System.Runtime.Interopservices;
namespace Foo
{
public class Project
{
[DllImport("project.dll")]
public static extern bool API_Init();
[DllImport("project.dll")]
public static extern bool API_Shutdown();
}
}
做上述防止的错位的名称,在调试和释放模式,不论产生"调试"的信息设定。好运气。
即使没有重整,32位和64位建立名称的出口不同,甚至与外部"C"。看看DEPENDS.EXE.
这可能意味着大麻烦到任何客户,并一LoadLibrary+GetProcAdress来访问您的功能。
因此,在所有其他人使用一个模块的定义文件如下:
LIBRARY MYDLL
EXPORTS
myFunction=myFunction
叶氏,这一点痛苦保持,但随后有多少出口功能做你写的一天?
此外,我通常变化的宏如下文所示,自从我Dll出口的功能不C++类和我想他们是可调用的大多数编程的环境:
#ifdef WTS_EXPORTS
#define WTS_API(ReturnType) extern "C" __declspec(dllexport) ReturnType WINAPI
#else
#define WTS_API(ReturnType) extern "C" __declspec(dllimport) ReturnType WINAPI
#endif
WTS_API(int) fnWTS(void);
最后一行中使用的混淆VisualAssistX几年前,我不知道,如果它恰当地的摘要,它现在:-)
我知道有多少次我试图迫使职能名称的使用代码和编译。我始终端用完全同样的事情,采用模块定义的文件(*.def)的末尾。和这里的原因是:
//---------------------------------------------------------------------------------------------------
// Test cases built using VC2010 - Win32 - Debug / Release << doesn't matter
//---------------------------------------------------------------------------------------------------
// SET: Project > Properties > Linker > Debugging > Generate Debug Info = Yes (/DEBUG)
// || (or, also doesn't matter)
// SET: Project > Properties > Linker > Debugging > Generate Debug Info = No + delete PDB file!
extern "C" __declspec(dllexport) void SetCallback(LPCALLBACK function);
> SetCallback
extern "C" __declspec(dllexport) void __stdcall SetCallback(LPCALLBACK function);
> _SetCallback@4
__declspec(dllexport) void SetCallback(LPCALLBACK function);
> ?SetCallback@@YAXP6AXHPADPAX@Z@Z
__declspec(dllexport) void __stdcall SetCallback(LPCALLBACK function);
> ?SetCallback@@YGXP6GXHPADPAX@Z@Z
//---------------------------------------------------------------------------------------------------
// this also big is nonsense cause as soon you change your calling convention or add / remove
// extern "C" code won't link anymore.
// doesn't work on other cases
#pragma comment(linker, "/EXPORT:SetCallback")
extern "C" __declspec(dllexport) void SetCallback(LPCALLBACK function);
// doesn't work on other cases
#pragma comment(linker, "/EXPORT:SetCallback=SetCallback")
extern "C" __declspec(dllexport) void SetCallback(LPCALLBACK function);
// doesn't work on other cases / creates alias
#pragma comment(linker, "/EXPORT:SetCallback=_SetCallback@4")
extern "C" __declspec(dllexport) void __stdcall SetCallback(LPCALLBACK function);
// doesn't work on other cases / creates alias
#pragma comment(linker, "/EXPORT:SetCallback=?SetCallback@@YAXP6AXHPADPAX@Z@Z")
__declspec(dllexport) void SetCallback(LPCALLBACK function);
// doesn't work on other cases / creates alias
#pragma comment(linker, "/EXPORT:SetCallback=?SetCallback@@YGXP6GXHPADPAX@Z@Z")
__declspec(dllexport) void __stdcall SetCallback(LPCALLBACK function);
//---------------------------------------------------------------------------------------------------
// So far only repetable case is using Module-Definition File (*.def) in all possible cases:
EXPORTS
SetCallback
extern "C" __declspec(dllexport) void SetCallback(LPCALLBACK function);
> SetCallback
extern "C" __declspec(dllexport) void __stdcall SetCallback(LPCALLBACK function);
> SetCallback
__declspec(dllexport) void SetCallback(LPCALLBACK function);
> SetCallback
__declspec(dllexport) void __stdcall SetCallback(LPCALLBACK function);
> SetCallback
// And by far this is most acceptable as it will reproduce exactly same exported function name
// using most common compilers. Header is dictating calling convention so not much trouble for
// other sw/ppl trying to build Interop or similar.
我不知道为什么没有人这样做,它把我只有10分钟,以测试所有情况。
该SomeFunction@@@23mangledstuff#@@@@出错得到的类型和类的C++的功能。简单的出口功能,是可调用从C即都写在C,或者是宣布的外部"C'C++编码。如果是你想要一个简单的接口,你必须做的功能,你的出口能使用只是C类型和使非成员能在全球名称空间。
基本上,当你用功能在C++、零件他们的名字现在包括他们的签名等等,以促进语言的功能,像超载。
如果你写一DLL使用声明影响(dllexport),那么它还应产生一个lib。链接,lib,你会被自动链接的功能登记的通过CRT在启动时间(如果你想起了以改变你的所有进口,出口品)。你不需要知道名字重整的,如果你用这个系统。
在情况下,它不清楚从数百行的华夫饼的主题上的错位的出口。这是我2c值:)
在创建一个项目称为Win32Project2使用VS2012年选出所有的符号中的向导。你应该有2个所谓的文件Win32Project2.cpp 和Win32project2.h
这些将参考一个例子可供出口的变量和一个例子出口的功能。
在Win32Project2.h你会有以下几种:
#ifdef WIN32PROJECT2_EXPORTS
#define WIN32PROJECT2_API __declspec(dllexport)
#else
#define WIN32PROJECT2_API __declspec(dllimport)
#endif
extern WIN32PROJECT2_API int nWin32Project2;
WIN32PROJECT2_API int fnWin32Project2(void);
到unmangle改变的最后两行到外部"C"声明:
extern "C" WIN32PROJECT2_API int nWin32Project2;
extern "C" WIN32PROJECT2_API int fnWin32Project2(void);
在Win32Project2.cpp 你还会有以下默认的定义:
// This is an example of an exported variable
WIN32PROJECT2_API int nWin32Project2=0;
// This is an example of an exported function.
WIN32PROJECT2_API int fnWin32Project2(void)
{
return 42;
}
到unmangle这些更改为:
// This is an example of an exported variable
extern "C" WIN32PROJECT2_API int nWin32Project2=0;
// This is an example of an exported function.
extern "C" WIN32PROJECT2_API int fnWin32Project2(void)
{
return 42;
}
基本上必须使用外部"C"前缀以前的声明,以便力的连接产生unmangled C喜欢的名字。
如果你喜欢使用改变后的姓名,为这些额外的混淆(情况下的重整的信息是有用的人以某种方式)使用"dumpbin/出口Win32Project2.dll"从VC命令行查找实际参考的名字。它将具有的形式"?fnWind32Project2@[param字节]@[其他信息].还有其他DLL视的工具,如果在运行一个VC命令不浮动你的船。
为什么毫不默认该公约是一个谜。实际重整的信息意味着什么(如参数字节的大小和更多的),这可能会有助于验证和调试,但是其他的废话.
进口DLL函数以上为C#项目(在这种情况下,一个基本的C#windows的应用程序形式上的,它包含的按钮"button1")这里的一些样品代号:
using System.Runtime.InteropServices;
namespace AudioRecApp
{
public partial class Form1 : Form
{
[ DllImport("c:\\Projects\test\Debug\Win32Projects2.dll")]
public static extern int fnWin32Project2();
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
int value;
value = fnWin32Project2();
}
}
}