Маршал. Маршал AllocHGlobal VS. AllocCoTaskMem, Маршал. SizeOf VS sizeof ()

У меня есть следующая структура:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct WAVEHDR
{
    internal IntPtr lpData;   // pointer to locked data buffer
    internal uint dwBufferLength; // length of data buffer
    internal uint dwBytesRecorded; // used for input only
    internal IntPtr dwUser;   // for client's use
    internal uint dwFlags;   // assorted flags (see defines)
    internal uint dwLoops;   // loop control counter
    internal IntPtr lpNext;  // reserved for driver
    internal IntPtr reserved;  // reserved for driver
}

Я должен выделить неуправляемую память для хранения экземпляра вышеупомянутой структуры. Указатель на эту структуру будет передан функциям waveOut win32 api (waveOutPrepareHeader, waveOutWrite, waveOutUnprepareHeader).

  1. Если я использую Marshal.AllocHGlobal() или Marshal.AllocCoTaskMem()? Каково различие?
  2. Если я передаю sizeof(WAVEHDR) или Marshal.SizeOf(typeof(WAVEHDR)) к методу выделения памяти? Каково различие?

ОБРАТИТЕ ВНИМАНИЕ, что выделенная память должна быть прикреплена.

23
задан Jon Seigel 5 March 2010 в 18:54
поделиться

3 ответа

Программа Windows всегда имеет как минимум две кучи, в которых выделяется неуправляемая память. Во-первых, это куча процесса по умолчанию, используемая Windows, когда ей необходимо выделить память от имени программы. Второй - это куча, используемая инфраструктурой COM для выделения. Маршаллер .NET P / Invoke предполагает, что эта куча использовалась любым неуправляемым кодом, подпись функции которого требует освобождения памяти.

AllocHGlobal выделяет из кучи процесса, AllocCoTaskMem выделяет из кучи COM.

Каждый раз, когда вы пишете неуправляемое взаимодействие код, вы всегда должны избегать ситуаций, когда код, выделяющий неуправляемую память, не совпадает с кодом, который ее освобождает. Велика вероятность того, что используется неправильный де-распределитель. Это особенно верно для любого кода, который взаимодействует с программой C / C ++. У таких программ есть собственный распределитель, который использует собственную кучу, создаваемую CRT при запуске. Выделение такой памяти в другом коде невозможно, вы не можете надежно получить дескриптор кучи. Это очень частый источник проблем с P / Invoke, особенно потому, что функция HeapFree () в XP и более ранних версиях молча игнорирует запросы на освобождение памяти, которая не была выделена в правой куче (утечка выделенной памяти), но Vista и Win7 вызывают сбой в работе программу с исключением.

Не нужно беспокоиться об этом в вашем случае, функции API mmsystem, которые вы используете, чисты. Они были разработаны, чтобы гарантировать, что тот же код, который выделяет, также освобождает. Это одна из причин, по которой вам нужно вызвать waveInPrepareHeader (), он выделяет буферы с тем же кодом, который в конечном итоге их освобождает. Вероятно, с кучей процесса по умолчанию.

Вам нужно только выделить структуру WAVEHDR. И вы несете ответственность за его выпуск, когда закончите с ним. API-интерфейсы mmsystem не делают этого за вас, прежде всего потому, что они не могут сделать это надежно. Соответственно, вы можете использовать любой распределитель, вам просто нужно обязательно вызвать соответствующий бесплатный метод. Все API Windows работают таким образом. Я использую CoTaskMemAlloc (), но на самом деле нет предпочтений. Просто, если я вызываю плохо спроектированный код, скорее всего, я буду использовать кучу COM.

Никогда не следует использовать sizeof () в сценарии взаимодействия. Он возвращает управляемый размер типа значения. Это может быть не то же самое после того, как маршаллер P / Invoke преобразовал тип структуры в соответствии с директивами [StructLayout] и [MarshalAs]. Только Marshal.SizeOf () дает вам гарантированно правильное значение.


ОБНОВЛЕНИЕ: в VS2012 произошли большие изменения. Библиотека времени выполнения C, включенная в нее, теперь выделяется из кучи процесса по умолчанию, а не из собственной кучи. В долгосрочной перспективе, что делает AllocHGlobal наиболее вероятным средством достижения успеха.

Библиотека времени выполнения C, включенная в нее, теперь выделяется из кучи процесса по умолчанию, а не из собственной кучи. В долгосрочной перспективе это делает AllocHGlobal наиболее вероятным средством достижения успеха.

Библиотека времени выполнения C, включенная в нее, теперь выделяется из кучи процесса по умолчанию, а не из собственной кучи. В долгосрочной перспективе, что делает AllocHGlobal наиболее вероятным средством достижения успеха.

43
ответ дан 29 November 2019 в 01:45
поделиться

2) Насколько мне известно, sizeof можно использовать только с типами, которые имеют предопределенный размер во время компиляции .

] Поэтому используйте Marshal.SizeOf (typeof (WAVEHDR)) .

1
ответ дан 29 November 2019 в 01:45
поделиться
Другие вопросы по тегам:

Похожие вопросы: