Может ли IntPtr быть преобразован в байтовый массив без использования Marshal.Copy? - PullRequest
23 голосов
/ 16 марта 2012

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

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

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

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

byte[] b = (byte[])intPtr

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

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

Ответы [ 4 ]

23 голосов
/ 16 марта 2012

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

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

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

Что касается длины, то нет способа узнать длину буфера неуправляемой памяти, кроме функции, котораяВыделенный буфер также говорит вам, какова длина.Это может быть сделано разными способами, как упоминали комментаторы (первое поле структуры, out-paramtere в методе).

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

8 голосов
/ 16 марта 2012

Попробуйте:

byte* b = (byte*)intPtr;

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

2 голосов
/ 16 марта 2012

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

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

1 голос
/ 16 марта 2012

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

...