Разметка структуры, содержащей int и int [] из C # в переполнение стека

У меня есть 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 ++ содержит разные данные.

Как я могу это исправить?

4

Решение

Так как 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);
4

Другие решения

Первое, что вы должны попробовать — это объявить ваш код 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
}
-1

Вы можете использовать PInvoke Interop Assistant. Вы просто вставляете объявление своей структуры и функции, и оно генерирует код C # для вас. Это помогло мне много раз.

-1
По вопросам рекламы [email protected]