我有一个用C ++编写的SDK来管理设备。我控制设备的程序是用C#编写的,所以CLI包装器类自然会在两种语言之间进行转换。我的C#项目将包装器包含为DLL。
我的问题是C ++ SDK使用指针指向数据数组。这些指针也可以在包装器中使用。
Wrapper .cpp代码:
Wrapper::Wrapper()
{
myData = new DataAquis(); //initiate C++ class's instance
}
int Wrapper::Start()
{
//(..)
int num = myData->Start();
ptr = (myData->img);
return num;
}
此代码初始化设备并创建指向数据结构的指针(unsigned char数组)。
Wrapper SDK .cpp代码:
int DataAquis::Start()
{
// (...)
// Pointer from SDK
img = pBuffer;
// (...)
return FAILED(nError) ? -1 : 0;
}
Wrapper .h代码:
public ref class Wrapper
{
public:
Wrapper();
// (...)
unsigned char *ptr;
private:
// (...)
};
代码C#:
public static Wrapper myDataAqui;
// (...)
private static void DataAquisition()
{
// call the start function in wrapper
myDataAqui.Start();
// Unsafe code for pointer use
unsafe
{
// point to aquired data
byte* imgptr1 = myDataAqui.ptr;
// AccesViolationException in above line.
// Data processing
for (y = 0; y < 256; y++)
{
for (x = 0; x < 320; x++)
{
int temp = x * 256 + 255 - y;
Spectrum1.X_Data_brut[bufferIndex][temp] = (UInt16)(*imgptr1++ + *imgptr1++ * 256);
aquirData[temp] = Spectrum1.X_Data_brut[bufferIndex][temp];
}
}
// (...)
}
}
如图所示,在我将Wrapper指针强制转换为本地字节指针的行上触发了AccessViolationException。
如果我在该行上设置了一个断点,我可以看到Wrapper指针正确指向一个内存地址,但是说它无法读取内存,因此指向的数据永远不会被收集在C#中。
我已经读过C ++中C#等效的无符号字符是一个字节,所以通常我应该读取相同数量的数据,并且永远不会超出我的数据结构的边界。
可能有用的附加信息:
你有任何想法如何解决这个问题?
答案 0 :(得分:1)
我不确定为什么你会得到一个异常,但我会把它编组到C ++ / CLI端的CLR数组中,所以在C#端不需要不安全的代码。
C ++ / CLI:
#include <vcclr.h>
#include <algorithm>
#pragma unmanaged
const int data_size = 100;
unsigned char * foo()
{
auto p = new unsigned char[data_size];
for (int i = 0; i < data_size; ++i)
p[i] = (unsigned char)i;
return p;
}
#pragma managed
public ref class Wrapper
{
public:
array<unsigned char>^ data;
void Start()
{
auto p = foo();
data = gcnew array<unsigned char>(data_size);
pin_ptr<unsigned char> data_pin = &data[0];
std::copy(p, p+data_size, (unsigned char *)data_pin);
}
};
C#:
class Program
{
static void Main(string[] args)
{
var wrapper = new Wrapper();
wrapper.Start();
System.Console.WriteLine($"{wrapper.data[15]}");
}
}
这将包含靠近源的任何可能的问题,并使调试更容易混淆。如果它在std :: copy中崩溃,那么你只是错误地使用你的C ++对象。