У меня есть следующая структура:
[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).
Marshal.AllocHGlobal()
или Marshal.AllocCoTaskMem()
? Каково различие?sizeof(WAVEHDR)
или Marshal.SizeOf(typeof(WAVEHDR))
к методу выделения памяти? Каково различие?ОБРАТИТЕ ВНИМАНИЕ, что выделенная память должна быть прикреплена.
Программа 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 наиболее вероятным средством достижения успеха.1) Marshal.AllocHGlobal точно будет работать. На основе документации для Marshal.AllocCoTaskMem, Marshal.AllocCoTaskMem тоже должен работать.
2) Используйте Marshal.SizeOf (typeof (WAVEHDR)). Хотя вы можете использовать метод Marshal.SizeOf, значение, возвращаемое этим методом, не всегда совпадает со значением, возвращаемым sizeof. Marshal.SizeOf возвращает размер после маршалинга типа, тогда как sizeof возвращает размер, выделенный средой CLR, включая любые отступы.
2) Насколько мне известно, sizeof
можно использовать только с типами, которые имеют предопределенный размер во время компиляции .
] Поэтому используйте Marshal.SizeOf (typeof (WAVEHDR))
.