У меня есть C ++ DLL с неуправляемым кодом и C # UI. Есть функция, импортированная из C ++ DLL, которая принимает записанную мной структуру в качестве параметра.
После маршалинга написанной мной структуры (MyImage) из C # в C ++ я могу получить доступ к содержимому массива int [] внутри него, но содержимое отличается. Я не знаю, чего мне здесь не хватает, так как я потратил довольно много времени и попробовал несколько хитростей, чтобы решить эту проблему (очевидно, недостаточно).
Структура MyImage в C #:
[StructLayout(LayoutKind.Sequential)]
struct MyImage
{
public int width;
public int height;
public int[] bits; //these represent colors of image - 4 bytes for each pixel
}
Структура MyImage в C ++:
struct MyImage
{
int width;
int height;
Color* bits; //typedef unsigned int Color;
MyImage(int w, int h)
{
bits = new Color[w*h];
}
Color GetPixel(int x, int y)
{
if (x or y out of image bounds) return UNDEFINED_COLOR;
return bits[y*width+x];
}
}
Объявление функции C # с MyImage в качестве параметра:
[DLLImport("G_DLL.dll")]
public static extern void DisplayImageInPolygon(Point[] p, int n, MyImage texture,
int tex_x0, int tex_y0);
Реализация C ++
DLLEXPORT void __stdcall DisplayImageInPolygon(Point *p, int n, MyImage img,
int imgx0, int imgy0)
{
//And below they have improper values (i don't know where they come from)
Color test1 = img.GetPixel(0,0);
Color test2 = img.GetPixel(1,0);
}
Поэтому при отладке проблемы я заметил, что массив MyImage.bits в структуре c ++ содержит разные данные.
Как я могу это исправить?
Так как bits
поле является указателем на память, выделенную в собственном коде, вам нужно объявить ее как IntPtr
в коде C #.
struct MyImage
{
public int width;
public int height;
public IntPtr bits;
}
Если вы хотите получить доступ к отдельным пикселям в коде C #, вам нужно написать GetPixel
метод, как вы сделали в коде C ++.
Обратите внимание, что так как bits
поле является указателем на память, выделенную в собственном коде, я ожидаю, что в реальном коде будет деструктор для структуры, которая вызывает delete[] bits
, В противном случае ваш код будет течь.
Это также означает, что вам нужно будет создавать и уничтожать экземпляры в собственном коде, и никогда не делать этого в управляемом коде. Вы придерживаетесь этой политики? Я подозреваю, что не на основе кода, который я могу увидеть здесь.
Вы также должны пересмотреть передачу struct
по значению. Вы действительно хотите взять его копию, когда вызываете эту функцию? Это означает, что у вас есть два экземпляра структуры, чьи bits
оба поля указывают на одну и ту же память. Но кому принадлежит эта память? Эта структура действительно должна быть передана по ссылке.
Я думаю, что у вас есть некоторые проблемы в вашем дизайне, но я не вижу достаточно кода или недостаточно знаю о вашей проблеме, чтобы иметь возможность дать вам конкретный совет.
В комментариях вы утверждаете, что ваша главная цель — перенести эти биты из кода C # в код C ++. Я предлагаю вам сделать это так:
MyImage* NewImage(int w, int h, Color* bits)
{
MyImage* img = new MyImage;
img->w = w;
img->h = h;
img->bits = new Color[w*h];
for (int i=0; i<w*h; i++)
img->bits[i] = bits[i];
return img;
}
void DeleteImage(MyImage* img)
{
delete[] img->bits;
delete img;
}
void DoSomethingWithImage(MyImage* img)
{
// do whatever it is you need to do
}
На стороне C # вы можете объявить это так:
[DllImport(@"dllname.dll", CallingConvention=CallingConvention.Cdecl)]
static extern IntPtr NewImage(int w, int h, int[] bits);
[DllImport(@"dllname.dll", CallingConvention=CallingConvention.Cdecl)]
static extern void DeleteImage(ImtPtr img);
[DllImport(@"dllname.dll", CallingConvention=CallingConvention.Cdecl)]
static extern void DoSomethingWithImage(ImtPtr img);
Первое, что вы должны попробовать — это объявить ваш код C # беззнаковыми типами int. Возможно, что один бит интерпретируется как знак для вашего int.
Так что в C # что-то вроде этого (просто обратите внимание, биты сейчас uint[]
):
[StructLayout(LayoutKind.Sequential)]
struct MyImage
{
public int width;
public int height;
public uint[] bits; //these represent colors of image - 4 bytes for each pixel
}
Вы можете использовать PInvoke Interop Assistant. Вы просто вставляете объявление своей структуры и функции, и оно генерирует код C # для вас. Это помогло мне много раз.