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

Можно ли включить IntPtr в массив байтов, не делая Marshal.Copy?

Я хочу получить данные из указателя IntPtr в массив байтов. Для этого я могу использовать следующий код:

IntPtr intPtr = GetBuff();
byte[] b = new byte[length];
Marshal.Copy(intPtr, b, 0, length);

Но приведенный выше код заставляет операцию копирования из IntPtr в массив байтов. Это нехорошее решение, когда данные велики.

Есть ли способ передать IntPtr в массив байтов? Например, будет ли следующая работа:

byte[] b = (byte[])intPtr

Это устранит необходимость в операции копирования.

Также: как определить длину данных, на которые указывает IntPtr?

4b9b3361

Ответ 1

Как уже упоминалось, невозможно сохранить данные в управляемом byte[] без копирования (с текущей структурой, которую вы предоставили *). Однако, если вам действительно не нужно, чтобы он находился в управляемом буфере, вы можете использовать операции unsafe для работы непосредственно с неуправляемой памятью. Это действительно зависит от того, что вам нужно с этим делать.

Все byte[] и другие ссылочные типы управляются сборщиком мусора CLR, и именно это отвечает за выделение памяти и освобождение, когда она больше не используется. Память, на которую указывает возврат GetBuffer, представляет собой блок неуправляемой памяти, выделенный кодом С++ и (в сторону макета памяти/подробности реализации в стороне) по существу полностью отделен от вашей управляемой памяти GC. Поэтому, если вы хотите использовать CLR-тип, управляемый GC (byte[]), чтобы содержать все данные, находящиеся в настоящее время в вашей неуправляемой памяти, на которые указывает ваш IntPtr, его необходимо переместить (скопировать) в память, которую знает GC около. Это можно сделать с помощью Marshal.Copy или с помощью настраиваемого метода с использованием кода unsafe или pinvoke или того, что у вас есть.

Однако это зависит от того, что вы хотите с ним делать. Вы упомянули о видеоданных. Если вы хотите применить какое-то преобразование или фильтр к данным, вы, вероятно, можете сделать это непосредственно в неуправляемом буфере. Если вы хотите сохранить буфер на диск, вы можете сделать это непосредственно в неуправляемом буфере.

По теме длины нет способа узнать длину неуправляемого буфера памяти, если функция, которая выделила буфер, также не сообщит вам, что такое длина. Это можно сделать многими способами, как отмечали комментаторы (первое поле структуры, вне параметров по методу).

* Наконец, если у вас есть контроль над кодом на С++, возможно, его можно будет изменить, чтобы он не отвечал за выделение буфера, в который он записывает данные, и вместо этого снабжен указателем на предварительно выделенный буфер. Затем вы могли бы создать управляемый byte[] в С#, предварительно выделенный для размера, необходимого вашему С++-коду, и использовать тип GCHandle для вывода это и указать указатель на ваш код на С++.

Ответ 2

Попробуйте следующее:

byte* b = (byte*)intPtr;

Требуется небезопасно (в флагом сигнатуры функции, блока или компилятора /unsafe).

Ответ 3

Невозможно, чтобы управляемый массив занимал неуправляемую память. Вы можете одновременно копировать неуправляемые данные по одному фрагменту и обрабатывать каждый фрагмент или создавать класс UnmanagedArray, который принимает IntPtr, и предоставляет индекс, который все равно будет использовать Marshal.Copy для доступа к данным.

Как отметил @Vinod, вы можете сделать это с помощью кода unsafe. Это позволит вам напрямую обращаться к памяти, используя указатели типа C. Тем не менее, вам нужно будет маршировать данные в управляемую память, прежде чем вы вызовете какой-либо небезопасный метод .NET, поэтому вы почти ограничены собственным C-подобным кодом. Я не думаю, что вам это вообще нужно потрудиться, просто напишите код на С++.

Ответ 4

Просмотрите эту страницу Code Project для решения проблемы работы с неуправляемыми массивами.