Маршал.AllocHGlobal против маршала.AllocCoTaskMem, Маршал.Оператор sizeof оператор 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)) метод выделения памяти? Что такое разница?

обратите внимание, что выделенная память должна быть закреплена.

3 ответов


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

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

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

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

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

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


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



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

чтобы использовать Marshal.SizeOf(typeof(WAVEHDR)).