Подтвердить что ты не робот

Правильный способ маршалировать SIZE_T *?

У меня есть следующее определение функции С++, которое я пытаюсь вызвать через PInvoke из управляемого кода:

bool FooBar(SIZE_T* arg1);

Моя управляемая декларация выглядела следующим образом:

[DllImport("mydll", SetLastError=true, CharSet=CharSet.Unicode)]
private static extern bool FooBar(ref uint arg1);

Некоторые из вас могут заметить ту же ошибку, которую я в конце концов сделал. Это не 64-битная портативная. SIZE_T имеет переменный размер (32-64 бит), как и указатель на него. В управляемом размере указатель правильно переводит на 64 бит, но uint не делает этого, и вы можете в итоге получить мусор в верхних битах arg1. Это была особенно стойкая ошибка, поскольку мусор часто был просто нулями: (

Единственное решение, которое я получил, это следующее управляемое объявление:

[DllImport("mydll", SetLastError=true, CharSet=CharSet.Unicode)]
private static extern bool FooBar(ref IntPtr arg1);

Это работает, конечно, потому что IntPtr может правильно изменить свой размер. В моем коде я просто рассматриваю IntPtr как целое число, и он работает, хотя он выглядит как уродливый хак. Мне кажется, должен быть какой-то способ указать это правильно, возможно, используя UnmanagedType.SysUInt, но я не смог найти какое-либо другое рабочее решение.

4b9b3361

Ответ 1

Использование IntPtr и/или UIntPtr делает это правильно - типы существуют специально для этой цели! Я не понимаю, почему вы считаете это "уродливым взломом". Я также не знаю, какова будет ваша предлагаемая альтернатива: любой атрибут, позволяющий сопоставлять значения с uint, будет по своей сути неправильным, потому что С# uint гарантированно будет 32-битным независимо от архитектуры и так что на 64-битной платформе, чтобы правильно ее маршалировать, ей пришлось бы обрезать половину, потерять данные и, вероятно, сделать результат бесполезным.

Ответ 2

UIntPtr - правильный тип.

size_t представляет собой целое число без знака, размер указателя и то, что означает UIntPtr. Я думаю, что "ptr" в названии может быть немного запутанным. Это на самом деле не означает, что "это указатель", это означает, что "это целочисленный размер указателя". Таким образом, ваше объявление будет выглядеть следующим образом:

[DllImport("mydll", SetLastError=true, CharSet=CharSet.Unicode)]
private static extern bool FooBar(ref UIntPtr arg1);