【发布时间】:2010-04-14 09:13:17
【问题描述】:
我在调用某些接受WAVEFORMATEX 结构作为参数的 WinAPI 函数时遇到问题。由于WAVEFORMATEX 结构的长度可以变化,我实现了一个WaveFormatEX 类,该类由一个自定义编组器类(实现ICustmoMarshaller)编组。这是 Aaron Lerch 在他的博客 (Part 1, Part 2) 中提供的示例,但在我这边做了一些修改。
当我从我的代码中调用 API 函数时,会调用自定义编组器的方法 MarshalManagedToNative 和 MarshalNativeToManaged,并且在 MarshalNativeToManaged 的末尾,托管对象包含正确的值强>。但是当执行返回到我的调用代码时,WaveFormatEx 对象不包含 API 调用期间读取的值。
所以问题是:为什么在本地 API 调用之后,正确地从本地编组回托管的数据没有显示在我的 WaveFormatEx 对象中?我在这里做错了什么?
编辑:
澄清一下,函数调用成功了,将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);
【问题讨论】:
标签: c# pinvoke marshalling