Я пытаюсь вызвать метод C ++ с помощью LoadLibrary, GetProcAddress и GetDelegateForFunctionPointer.
Все в порядке (в выпуске и отладке), если я запускаю приложение .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);
Если у кого-то есть идеи, было бы здорово!
P / Invoke был в основном предназначен для взаимодействия с Windows API, поэтому в StdCall
соглашение по умолчанию. C использует Cdecl
соглашение по умолчанию. Вам нужно изменить одну из сторон, чтобы явно указать соглашение о вызовах, чтобы оно совпадало с обеими сторонами.
Ваш классический импорт DLL определяет соглашение с [DllImport(..., CallingConvention=CallingConvention.Cdecl)
Вариант, основанный на GetDelegateForFunctionPointer
не определяет соглашение о вызовах (и, следовательно, использует StdCall
). Вы должны указать это с [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
,
Ваш код такой же неправильный без отладчика, он просто скрывает ошибку. Обычно такое несоответствие нарушает балансировку указателя стека, приводя к мгновенному сбою, но код маршаллинга .net, кажется, имеет специальную обработку для указателя стека, избегая этого сбоя. Без отладчика молча глотает ошибку, с помощью отладчика она ее отображает.
Других решений пока нет …