我试图通过使用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);
如果有人有任何想法,那就太棒了!
答案 0 :(得分:4)
P / Invoke主要用于与Windows API互操作,因此默认情况下使用StdCall
约定。 C默认使用Cdecl
约定。您需要更改两侧以明确指定调用约定,以便它在两侧都匹配。
您的经典DLL导入使用[DllImport(..., CallingConvention=CallingConvention.Cdecl)
指定约定,基于GetDelegateForFunctionPointer
的变体未指定调用约定(因此使用StdCall
)。您需要使用[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
指定它。
如果没有附加调试器,您的代码就是错误的,它只是隐藏了错误。通常这种不匹配会导致堆栈指针失去平衡,导致即时崩溃,但.net编组代码似乎对堆栈指针有特殊处理,以避免崩溃。如果没有调试器,则会默默地吞下错误,并使用调试器显示错误。