调用native(DllImport)函数

时间:2015-06-09 13:51:46

标签: c# .net stack-overflow dllimport

我目前正在做微基准测试,以便更好地理解本机代码性能的clr。在下面的示例中,我得到一个StackOverflowException,当编译为release并在没有附加调试器的情况下执行。编译为debug-build或运行附带调试器的程序时,我没有得到异常。此外,我也只能使用SuppressUnmanagedCodeSecurityAttribute - 属性

来获取此错误

我使用c和VS2013(platformtoolset = v120)构建了一个dll,其中包含一个函数:

__declspec(dllexport) int __cdecl NativeTestFunction(int a, int b, int c, int d)
{
    return a + c + b + d;
}

在我的C#程序中,我使用DllImport来调用此函数并进行一些时序测量:

[DllImport("Native.dll", EntryPoint = "NativeTestFunction")]
static extern int NativeTestFunction(int a, int b, int c, int d);

[DllImport("Native.dll", EntryPoint = "NativeTestFunction"), SuppressUnmanagedCodeSecurityAttribute]
static extern int NativeTestFunctionSuppressed(int a, int b, int c, int d);

static void Main(string[] args)
{
    byte[] data = new byte[64];
    int c = 0;

    Stopwatch sw = Stopwatch.StartNew();

    for (int i = 0; i < 10000000; i++)
        c += NativeTestFunction(2, -1, -2, 1);

    Console.WriteLine("Unsuppressed: " + sw.Elapsed.ToString());
    sw = Stopwatch.StartNew();

    for (int i = 0; i < 10000000; i++)
        c += NativeTestFunctionSuppressed(2, -1, -2, 1);

    Console.WriteLine("Suppressed..: " + sw.Elapsed.ToString());
}

如果我将此代码编译为release并在未连接调试器的情况下启动它,则输出为:

Unsuppressed: 00:00:00.2666255

Process is terminated due to StackOverflowException.

但是,在调试器附加或编译为调试的情况下执行,并且无论是否附带调试器启动,程序都会成功:

Unsuppressed: 00:00:00.2952272
Suppressed..: 00:00:00.1278980

这是.NET / CLR中的已知错误吗?我的错误是什么?我认为附加和未连接的调试器之间的行为应该相同。

.NET 2.0和.NET 4.0发生此错误。我的软件编译为x86(因此仅针对x86进行测试)以兼容Native.dll。如果您不想自己设置此方案,可以下载我的测试项目:Sourcecode

1 个答案:

答案 0 :(得分:5)

__declspec(dllexport) int __cdecl NativeTestFunction(int a, char* b, int c, int d)

请注意b的类型。它是char*。然后在你编写的C#代码中:

[DllImport("Native.dll", EntryPoint = "NativeTestFunction"), 
    SuppressUnmanagedCodeSecurityAttribute]
static extern int NativeTestFunctionSuppressed(int a, int b, int c, int d);

您在此声明bint。那不匹配。调用函数时会变得更糟。

NativeTestFunctionSuppressed(2, -1, -2, 1);

传递-1将在32位进程中等同于传递地址0xffffffff。尝试取消引用该地址没有任何好处。

另一个问题是调用约定不匹配。本机代码使用__cdecl,但托管代码使用默认值__stdcall。将托管代码更改为:

[DllImport("Native.dll", EntryPoint = "NativeTestFunction", 
    CallingConvention = CallingConvention.Cdecl), 
    SuppressUnmanagedCodeSecurityAttribute]

同样适用于其他导入。