PInvoke работает только в 64-битной версии при возврате структуры - PullRequest
1 голос
/ 24 июня 2019

У меня есть следующий код C ++, который компилируется в dll:

typedef struct _RGB {
    unsigned char R, G, B;
} RGB;

extern "C" __declspec(dllexport) RGB __stdcall TestMethod1() {
    RGB rgb{1,2,3};
    return rgb;
}

и звоню в C #, используя:

static void Main(string[] args)
{
    var res = TestMethod1();
}

[DllImport(@"D:\Develop\res\VSProjects\ConsoleApp1\Debug\Dll1.dll", CallingConvention = CallingConvention.StdCall)]
static extern RGB TestMethod1();

[StructLayout(LayoutKind.Sequential)]
struct RGB { public byte R, G, B; }

При запуске под x86, после сборки dll под x86 я получаю ошибку Attempted to read or write protected memory.. В x64 работает нормально.

Когда я использую управляемый / собственный отладчик, я вижу, что он падает на return rgb;.

При изменении типа возвращаемого значения на long (int в C #) он отлично работает даже при x86.

RGB struct является blittable , так почему я получаю эту проблему?

1 Ответ

1 голос
/ 24 июня 2019

Не используйте struct для «сложных» возвращаемых типов, предпочитайте что-то вроде этого:

C ++:

extern "C" __declspec(dllexport) void __stdcall TestMethod2(RGB *prgb) {
    prgb->R = 1;
    prgb->G = 2;
    prgb->B = 3;
}

C #:

[DllImport(@"D:\smo\source\repos\ConsoleApplication4\Debug\Dll1.dll")]
static extern void TestMethod2(ref RGB rgb);

static void Main(string[] args)
{
    var rgb = new RGB();
    TestMethod2(ref rgb);
}

Примечание вв вашем конкретном случае это не удается, потому что размер структуры равен 3, поэтому вы можете заставить его работать, если вы измените структуру, например, следующим образом:

C ++:

typedef struct _RGB {
    unsigned char R, G, B, A;
} RGB;

C #

[StructLayout(LayoutKind.Sequential)]
struct RGB { public byte R, G, B, A; }

При этом определении размер будет равен 4, поэтому компилятор C ++ сгенерирует код, который будет возвращать значение int32 вместо того, чтобы возвращать - вероятно - ссылку на некоторую внутреннюю память, которая будет утеряна во время выполнения.достигает стороны .NET.Это чистая удача (или хак), и я думаю, что это зависит от компилятора C ++.

...