I have a SDK written in C++ which manages a device. My program controlling the device is written in C#, so naturally a CLI wrapper class does the translation between both languages. My C# project includes the wrapper as a DLL.
My issue is that the C++ SDK is using pointers to head to arrays of data. These pointers are also available in the wrapper.
Wrapper .cpp code:
Wrapper::Wrapper()
{
myData = new DataAquis(); //initiate C++ class's instance
}
int Wrapper::Start()
{
//(..)
int num = myData->Start();
ptr = (myData->img);
return num;
}
This code initializes the device and creates a pointer to a data structure (array of unsigned char).
Wrapper SDK .cpp code:
int DataAquis::Start()
{
// (...)
// Pointer from SDK
img = pBuffer;
// (...)
return FAILED(nError) ? -1 : 0;
}
Wrapper .h code:
public ref class Wrapper
{
public:
Wrapper();
// (...)
unsigned char *ptr;
private:
// (...)
};
Code 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];
}
}
// (...)
}
}
As shown, an AccessViolationException is triggered at the line where I cast the Wrapper pointer to a local byte pointer.
If I put a breakpoint on that line, I can see that the Wrapper pointer correctly points to a memory address, but says that it is unable to read memory, so the pointed data is never gathered in C#.
I have read that the C# equivalent of an unsigned char in C++ is a byte, so normally I should read the same amount of data and never go outside the boundaries of my data structure.
Additionnal information that could be useful:
Do you have any ideas how to fix this ?
I'm not sure why you're getting an exception but I'd marshal it into a CLR array on the C++/CLI side so no unsafe code is needed on the C# side.
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]}");
}
}
This will contain any possible problems close to the source and make debugging a lot less confusing. If it crashes in std::copy then you're just using your C++ object wrong.