I am trying to call a C++ method by using LoadLibrary, GetProcAddress and GetDelegateForFunctionPointer.

Everything is ok (in release and debug) if I run the .NET 4.0 application (Ctrl + F5). But when I start debug mode (F5), the program crash when I invoke the C++ method.

The .cpp :

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

The .h:

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

The .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);
    }
}
}

If I use a classical DLL import like below, it works but it is not what I want to achieve :

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

If someone has any idea, it would be great !

有帮助吗?

解决方案

P/Invoke was mainly designed to interoperate with the Windows API, so in uses the StdCall convention by default. C uses the Cdecl convention by default. You need to change on of the sides to explicitly specify the calling convention so it matches on both sides.

Your classical DLL import specifies the convention with [DllImport(..., CallingConvention=CallingConvention.Cdecl), the variant based on GetDelegateForFunctionPointer does not specify a calling convention (and thus uses StdCall). You need to specify it with [UnmanagedFunctionPointer(CallingConvention.Cdecl)].

Your code is just as wrong without a debugger attached, it just hides the error. Normally such a mismatch would unbalance the stackpointer leading to an instant crash, but the .net marshalling code seems to have special handling for the stackpointer avoiding that crash. Without a debugger is silently swallows the error, with a debugger it displays it.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top