В программе Windows всегда есть как минимум две кучи, в которых выделена неуправляемая память. Во-первых, это куча процесса по умолчанию, используемая Windows, когда ему требуется выделить память от имени программы. Вторая - куча, используемая инфраструктурой COM для распределения. Маршаллер .NET P/Invoke предполагает, что эта куча использовалась любым неуправляемым кодом, чья подпись функции требует де-выделения памяти.
AllocHGlobal выделяет из кучи процесса, AllocCoTaskMem выделяет из кучи COM.
Всякий раз, когда вы пишете неуправляемый код взаимодействия, вы всегда должны избегать ситуации, когда код, который выделяет неуправляемую память, не совпадает с кодом, который освобождает его. Было бы неплохо, если используется неправильный разделитель. Это особенно верно для любого кода, который перехватывает программу C/C++. Такие программы имеют свой собственный распределитель, который использует свою собственную кучу, созданную ЭЛТ при запуске. Отмена выделения такой памяти в другом коде невозможна, вы не можете надежно получить дескриптор кучи. Это очень распространенный источник проблем P/Invoke, особенно потому, что функция HeapFree() в XP и ранее молча игнорирует запросы на бесплатную память, которая не была выделена в правой куче (утечка выделенной памяти), но Vista и Win7 с исключением.
Не беспокойтесь об этом в вашем случае, функции API mmsystem, которые вы используете, чисты. Они были разработаны для обеспечения того же кода, который выделяет также освобождает. Это одна из причин, по которым вы должны вызвать waveInPrepareHeader(), она выделяет буферы с тем же кодом, который в конечном итоге освобождает их. Возможно, с кучей процесса по умолчанию.
Вам нужно всего лишь выделить структуру WAVEHDR. И вы несете ответственность за его освобождение, когда вы закончите с этим. API-интерфейсы mmsystem не делают этого для вас, прежде всего потому, что они не могут сделать это надежно. Соответственно, вы можете использовать либо распределитель, вам просто нужно обязательно вызвать соответствующий бесплатный метод. Все Windows API работают таким образом. Я использую CoTaskMemAlloc(), но на самом деле это не так. Просто, если я называю плохо разработанный код, немного лучше использовать кучу COM.
Вы никогда не должны использовать sizeof() в сценарии взаимодействия. Он возвращает управляемый размер типа значения. Возможно, это не так, если маршаллер P/Invoke перевел тип структуры в соответствии с директивами [StructLayout] и [MarshalAs]. Только Marshal.SizeOf() дает вам гарантированное правильное значение.
ОБНОВЛЕНИЕ: в VS2012 произошли большие изменения. Библиотека времени выполнения C, включенная в нее, теперь выделяет из кучи процесса по умолчанию вместо использования своей собственной кучи. Долгосрочный, что делает AllocHGlobal наиболее вероятным средством для успеха.
Существуют ли различия в производительности между двумя функциями распределения? – DxCK
'AllocCoTaskMem' более совершенен. 'AllocHGlobal' вызывает' LocalAlloc', который имеет следующее примечание: «Локальные функции имеют большие накладные расходы и предоставляют меньше функций, чем другие функции управления памятью». См. Https://msdn.microsoft.com/en-us/library/windows/desktop/aa366723(v=vs.85).aspx – IamIC