如何在 C# 中从非托管 C++ DLL 正确调用方法?
How to correctly call methods from unmanaged C++ DLL in C#?
我有一个用 C++ API 控制的采集板。我想直接从我的 C# 应用程序调用这些方法。
这些是导致问题的方法:
DLL:
// Read the DATA of the board
SPINAPI int pb_get_data(unsigned int num_points, int *real_data, int *imag_data);
// Write plain ASCII file for the data returned from pb_get_data(..)
SPINAPI int pb_write_ascii(const char *fname, int num_points, float SW, float SF, const int *real_data, const int *imag_data);
其中SPINAPI
定义如下:
#ifdef __WINDOWS__
#ifdef DLL_EXPORTS
#define SPINAPI __declspec(dllexport)
#else
#define SPINAPI __declspec(dllimport)
#endif
#else
#define SPINAPI
#endif
C#:
[DllImport(@"C:\SpinCore\SpinAPI\lib32\spinapi.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int pb_get_data(uint num_points, [MarshalAs(UnmanagedType.LPArray)] ref int[] real_data, [MarshalAs(UnmanagedType.LPArray)] ref int[] imag_data);
[DllImport(@"C:\SpinCore\SpinAPI\lib32\spinapi.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int pb_write_ascii(string fname, int num_points, float SW, [MarshalAs(UnmanagedType.LPArray)] ref int[] real_data, [MarshalAs(UnmanagedType.LPArray)] ref int[] imag_data);
调用时 pb_get_data()
,
pb_get_data((uint)numberOfPoints, ref idata, ref idata_imag);
我收到以下错误:
System.AccessViolationException was unhandled
Message: An unhandled exception of type 'System.AccessViolationException' occurred in Unknown Module.
Additional information: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
调用时 pb_write_ascii()
,
pb_write_ascii(@"data\direct_data_0.txt", numberOfPoints, (float)actualSW, ref idata, ref idata_imag);
其中:
int[] idata = new int[MAX_NUMBER_POINTS];
int[] idata_imag = new int[MAX_NUMBER_POINTS];
没有任何反应(文件未写入)。
有人知道我做错了什么以及如何纠正这些问题吗?我提到我可以从 DLL 中成功调用其他方法。
使用 C++/Cli 包装库可能是一种可能的解决方案。
您应该创建 C++/Cli 库,其中将包含这样的代码:
namespace ManagedCode {
public ref class WrappedFunctions
{
public:
static int pb_get_data(unsigned int num_points, array<int>^ real_data, array<int>^ imag_data)
{
pin_ptr<int> temp_real_data = &real_data[0];
pin_ptr<int> temp_imag_data = &imag_data[0];
return UnManagedCode::pb_get_data(num_points, temp_real_data, temp_imag_data);
}
};
}
在其他情况下,您可以使用编组函数
有关详细信息,请阅读
https://msdn.microsoft.com/ru-ru/library/1dz8byfh.aspx
根据 Hans Passant 的说法,删除 ref
关键字是导致问题的原因。删除它解决了问题。
我有一个用 C++ API 控制的采集板。我想直接从我的 C# 应用程序调用这些方法。
这些是导致问题的方法:
DLL:
// Read the DATA of the board
SPINAPI int pb_get_data(unsigned int num_points, int *real_data, int *imag_data);
// Write plain ASCII file for the data returned from pb_get_data(..)
SPINAPI int pb_write_ascii(const char *fname, int num_points, float SW, float SF, const int *real_data, const int *imag_data);
其中SPINAPI
定义如下:
#ifdef __WINDOWS__
#ifdef DLL_EXPORTS
#define SPINAPI __declspec(dllexport)
#else
#define SPINAPI __declspec(dllimport)
#endif
#else
#define SPINAPI
#endif
C#:
[DllImport(@"C:\SpinCore\SpinAPI\lib32\spinapi.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int pb_get_data(uint num_points, [MarshalAs(UnmanagedType.LPArray)] ref int[] real_data, [MarshalAs(UnmanagedType.LPArray)] ref int[] imag_data);
[DllImport(@"C:\SpinCore\SpinAPI\lib32\spinapi.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int pb_write_ascii(string fname, int num_points, float SW, [MarshalAs(UnmanagedType.LPArray)] ref int[] real_data, [MarshalAs(UnmanagedType.LPArray)] ref int[] imag_data);
调用时 pb_get_data()
,
pb_get_data((uint)numberOfPoints, ref idata, ref idata_imag);
我收到以下错误:
System.AccessViolationException was unhandled
Message: An unhandled exception of type 'System.AccessViolationException' occurred in Unknown Module.
Additional information: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
调用时 pb_write_ascii()
,
pb_write_ascii(@"data\direct_data_0.txt", numberOfPoints, (float)actualSW, ref idata, ref idata_imag);
其中:
int[] idata = new int[MAX_NUMBER_POINTS];
int[] idata_imag = new int[MAX_NUMBER_POINTS];
没有任何反应(文件未写入)。
有人知道我做错了什么以及如何纠正这些问题吗?我提到我可以从 DLL 中成功调用其他方法。
使用 C++/Cli 包装库可能是一种可能的解决方案。 您应该创建 C++/Cli 库,其中将包含这样的代码:
namespace ManagedCode {
public ref class WrappedFunctions
{
public:
static int pb_get_data(unsigned int num_points, array<int>^ real_data, array<int>^ imag_data)
{
pin_ptr<int> temp_real_data = &real_data[0];
pin_ptr<int> temp_imag_data = &imag_data[0];
return UnManagedCode::pb_get_data(num_points, temp_real_data, temp_imag_data);
}
};
}
在其他情况下,您可以使用编组函数
有关详细信息,请阅读 https://msdn.microsoft.com/ru-ru/library/1dz8byfh.aspx
根据 Hans Passant 的说法,删除 ref
关键字是导致问题的原因。删除它解决了问题。