Может ли IntPtr быть приведен в массив байтов без Маршала.Копия?
Я хочу получить данные из Указателя IntPtr в массив байтов. Для этого я могу использовать следующий код:
IntPtr intPtr = GetBuff();
byte[] b = new byte[length];
Marshal.Copy(intPtr, b, 0, length);
но приведенный выше код заставляет операцию копирования из IntPtr в массив байтов. Это не очень хорошее решение, когда данные, о которых идет речь, большие.
есть ли способ привести IntPtr к массиву байтов? Например, будет ли работать следующее:
byte[] b = (byte[])intPtr
это исключило бы потребность для экземпляра операция.
также: как мы можем определить длину данных, на которые указывает IntPtr?
4 ответов
как упоминали другие, вы не можете хранить данные в управлял byte[]
без копирования (с текущей структурой, которую вы предоставили*). Однако, если вы на самом деле нужно чтобы быть в управляемом буфере, вы можете использовать unsafe
операции для работы непосредственно с неуправляемой памяти. Все зависит от того, что с ним делать.
все byte[]
и другие ссылочные типы управляются сборщиком мусора CLR, и это что отвечает за выделение памяти и освобождение, когда она больше не используется. Воспоминание, на которое указывает возвращение GetBuffer
- это блок неуправляемой памяти, выделенный кодом C++, и (макет памяти / детали реализации в сторону) по существу полностью отделен от вашей управляемой памяти GC. Поэтому, если вы хотите использовать управляемый GC тип CLR (byte[]
), чтобы содержать все данные, которые в настоящее время хранятся в вашей неуправляемой памяти, на которую указывает ваш IntPtr
, его нужно переместить (скопировать) в память, о которой знает GC. Это можно сделать с помощью Marshal.Copy
или пользовательским методом с помощью unsafe
код или pinvoke или что у вас есть.
однако, это зависит от того, что вы хотите сделать с ним. Вы упомянули, что это видеоданные. Если вы хотите применить некоторое преобразование или фильтр к данным, Вы можете сделать это непосредственно в неуправляемом буфере. Если вы хотите сохранить буфер на диск, вы, вероятно, можете сделать это непосредственно на неуправляемом буфере.
по теме длина, невозможно узнать длину неуправляемого буфера памяти, если функция, которая выделила буфер, также не сообщает вам, какова его длина. Это можно сделать множеством способов, как упоминали комментаторы (первое поле структуры, out paramtere по методу).
*наконец, если у вас есть контроль над кодом C++, возможно, его можно изменить, чтобы он не отвечал за выделение буфера, в который он записывает данные, а вместо этого снабжен указателем на предварительно выделенный буфер. Затем вы можете создать управлял byte[]
В C#, предварительно выделенный размер, требуемый вашим кодом C++, и используйте GCHandle
введите, чтобы закрепить его и указать указатель на код C++.
попробуйте это:
byte* b = (byte*)intPtr;
требует небезопасных (в сигнатуре функции, блоке или флаге компилятора /unsafe
).
нельзя, чтобы управляемый массив занимал неуправляемую память. Вы можете скопировать неуправляемые данные по одному фрагменту за раз и обработать каждый фрагмент или создать UnmanagedArray
класс, который принимает IntPtr
и предоставляет индексатор, который по-прежнему будет использовать Marshal.Копию для доступа к данным.
как отметил @Vinod, вы можете сделать это с помощью unsafe
код. Это позволит вам получить доступ к памяти напрямую, используя C-подобных указателей. Однако вам нужно будет маршалировать данные в управляемые память перед вызовом любого небезопасного метода .NET, поэтому вы в значительной степени ограничены своим собственным C-подобным кодом. Я не думаю, что вам стоит беспокоиться об этом вообще, просто напишите код на C++.
зацените Проект Код страница для решения проблемы работы с неуправляемыми массивами.