我在VS中创建了新的Win32项目,并为此目标选择了动态库( *.dll)。
我在主文件中定义了一些导出功能:
__declspec(dllexport)
int TestCall(void)
{
int value = 4 / 2;
std::cout << typeid(value).name() << std::endl;
return value;
}
__declspec(dllexport)
void SwapMe(int *first, int *second)
{
int tmp = *first;
*first = *second;
*second = tmp;
}
当我查看垃圾箱/出口时,我有:
ordinal hint RVA name
1 0 00001010 ?SwapMe@@YAXPEAH0@Z
2 1 00001270 ?TestCall@@YAHXZ
我在这样的C#版本中打电话:
[DllImport(@"lib1.dll", EntryPoint = "?TestCall@@YAHXZ",
CallingConvention = CallingConvention.Cdecl)]
static extern int TestCall();
这不是使用导出方法的正确形式。在C DLL项目中生成此类名称的我在哪里失败?
这是正常的,C 编译器将名称装饰应用于函数。C 语言支持功能超载,就像C#一样。因此,您可以编写Foo(int)
和Foo(double)
功能。显然,它们都不能以名为" foo"的函数导出,客户代码不知道该拨打哪个函数。因此,额外的字符编码名称,以使其对超载是唯一的。
您可以通过声明函数extern "C"
,C语言不支持超载,因此不需要相同的装饰。
但是,如果不这样做,那实际上更好。因为这也是捕获错误的绝佳方法。就像更改C 代码中的函数声明一样,但忘记在C#代码中修改PINVOKE声明。现在,您将易于诊断出"未找到的入口点"异常,而不是不描述性,并且很难诊断accessVioLationException。不一定必须在C 代码中提高,堆栈不平衡也可能会使您的C#代码崩溃。查找装饰的名称有点痛苦,但是,通过要求链接器创建地图文件(/地图选项)来改进它。
使用extern" c"指定链接以避免名称mangling:
extern "C" __declspec(dllexport) int TestCall(void);
extern "C" __declspec(dllexport) void SwapMe(int *first, int *second);