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 theCdecl
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 onGetDelegateForFunctionPointer
does not specify a calling convention (and thus usesStdCall
). 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.