1

我试图通过使用 LoadLibrary、GetProcAddress 和 GetDelegateForFunctionPointer 来调用 C++ 方法。

如果我运行 .NET 4.0 应用程序 (Ctrl + F5),一切正常(在发布和调试中)。但是当我启动调试模式(F5)时,当我调用 C++ 方法时程序崩溃。

.cpp :

#include "PointEntree.h"
#include <stdio.h>
extern "C" __declspec( dllexport ) int Test1(int a)
{
    printf("coucou\n");
    return 0;
}

.h:

extern "C" __declspec( dllexport ) int Test1(int);

.cs :

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;

namespace NETProgram
{
static class NativeMethods
{
    [DllImport("kernel32.dll")]
    public static extern IntPtr LoadLibrary(string dllToLoad);

    [DllImport("kernel32.dll")]
    public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);

    [DllImport("kernel32.dll")]
    public static extern bool FreeLibrary(IntPtr hModule);
}

class Program
{      
    delegate int Bambou_Test1(int i);

    static void Main(string[] args)
    {
        IntPtr pDll = NativeMethods.LoadLibrary(@"E:\Dev\C#\ImportC++\Bambou\Release\Bambou.dll");
        IntPtr pAddressOfFunctionToCall = NativeMethods.GetProcAddress(pDll, "Test1");

        Bambou_Test1 method = (Bambou_Test1)Marshal.GetDelegateForFunctionPointer(pAddressOfFunctionToCall, typeof(Bambou_Test1));
        method.Invoke(12);
    }
}
}

如果我使用像下面这样的经典 DLL 导入,它可以工作,但这不是我想要实现的:

[DllImport(@"E:\Dev\C#\ImportC++\Bambou\Debug\Bambou.dll", EntryPoint = "Test1",  CallingConvention=CallingConvention.Cdecl)]
public static extern int Test1(int a);

如果有人有任何想法,那就太好了!

4

1 回答 1

4

P/Invoke 主要设计用于与 Windows API 互操作,因此 inStdCall默认使用约定。CCdecl默认使用约定。您需要更改两侧以显式指定调用约定,使其在两侧匹配。

您的经典 DLL 导入使用 指定约定[DllImport(..., CallingConvention=CallingConvention.Cdecl),基于的变体GetDelegateForFunctionPointer未指定调用约定(因此使用StdCall)。您需要用 指定它[UnmanagedFunctionPointer(CallingConvention.Cdecl)]

您的代码在没有附加调试器的情况下同样错误,它只是隐藏了错误。通常这种不匹配会使堆栈指针失衡,从而导致即时崩溃,但 .net 编组代码似乎对堆栈指针进行了特殊处理,从而避免了该崩溃。没有调试器会默默地吞下错误,使用调试器会显示它。

于 2013-12-11T21:26:09.997 回答