У меня проблема с PInvoking некоторых функций WinAPI, которые принимают WAVEFORMATEX
структуры в качестве параметров.Поскольку длина структуры WAVEFORMATEX
может варьироваться, я реализовал класс WaveFormatEX, который маршалируется специальным классом маршаллера (который реализует ICustmoMarshaller
).Это следует примеру Аарона Лерча в его блоге ( Часть 1 , Часть 2 ), но с некоторыми изменениями с моей стороны.
Когда я звонюфункция API из моего кода, методы MarshalManagedToNative
и MarshalNativeToManaged
пользовательского маршаллера вызываются, а в конце MarshalNativeToManaged
, управляемый объект содержит правильные значения .Но когда выполнение возвращается к моему вызывающему коду, объект WaveFormatEx
не содержит значений, считанных во время вызова API .
Таким образом, вопрос заключается в следующем: почему данные, которые правильно перенаправлены из нативного в управляемый, не отображаются в моем WaveFormatEx
объекте после нативного вызова API?Что я здесь не так делаю?
Редактировать:
Для пояснения, вызов функции завершается успешно, так же как и маршалинг объекта WaveFormatEx
обратно в управляемый код.Как только выполнение возвращается из метода маршаллинга в область, из которой был вызван метод, объект WaveFormatEx
, который был объявлен в этой области вызова, не содержит данных результата.
Вот прототип функции и класс WaveFormatEx:
[DllImport("avifil32.dll")]
public static extern int AVIStreamReadFormat(
int Stream,
int Position,
[In, Out, MarshalAs(UnmanagedType.CustomMarshaler,
MarshalTypeRef = typeof(WaveFormatExMarshaler))]
WaveFormatEx Format,
ref int Size
);
[StructLayout(LayoutKind.Sequential)]
public class WaveFormatEx
{
public int FormatTag;
public short Channels;
public int SamplesPerSec;
public int AvgBytesPerSec;
public short BlockAlign;
public short BitsPerSample;
public short Size;
public byte[] AdditionalData;
public WaveFormatEx(short AdditionalDataSize)
{
WaveFormat.Size = AdditionalDataSize;
AdditionalData = new byte[AdditionalDataSize];
}
}
Методы сортировки выглядят следующим образом:
public object MarshalNativeToManaged(System.IntPtr NativeData)
{
WaveFormatEx ManagedObject = new WaveFormatEx(0);
ManagedObject = (WaveFormatEx)Marshal.PtrToStructure(
NativeData, typeof(WaveFormatEx));
ManagedObject.AdditionalData = new byte[ManagedObject.Size];
// If there is extra data, marshal it
if (ManagedObject.WaveFormat.Size > 0)
{
NativeData = new IntPtr(
NativeData.ToInt32() +
Marshal.SizeOf(typeof(WaveFormatEx)));
ManagedObject.AdditionalData = new byte[ManagedObject.WaveFormat.Size];
Marshal.Copy(NativeData, ManagedObject.AdditionalData, 0,
ManagedObject.WaveFormat.Size);
}
return ManagedObject;
}
public System.IntPtr MarshalManagedToNative(object Object)
{
WaveFormatEx ManagedObject = (WaveFormatEx)Object;
IntPtr NativeStructure = Marshal.AllocHGlobal(
GetNativeDataSize(ManagedObject) + ManagedObject.WaveFormat.Size);
Marshal.StructureToPtr(ManagedObject, NativeStructure, false);
// Marshal extra data
if (ManagedObject.WaveFormat.Size > 0)
{
IntPtr dataPtr = new IntPtr(NativeStructure.ToInt32()
+ Marshal.SizeOf(typeof(WaveFormatEx)));
Marshal.Copy(ManagedObject.AdditionalData, 0, dataPtr, Math.Min(
ManagedObject.WaveFormat.Size,
ManagedObject.AdditionalData.Length));
}
return NativeStructure;
}
И это мой код вызова:
WaveFormatEx test = new WaveFormatEx(100);
int Size = System.Runtime.InteropServices.Marshal.SizeOf(test);
// After this call, test.FormatTag should be set to 1 (PCM audio),
// but it is still 0, as well as all the other members
int Result = Avi.AVIStreamReadFormat(AudioStream, 0, test, ref Size);