C# waveOutPrepareHeader返回无效参数

C# waveOutPrepareHeader返回无效参数,c#,audio,windows-ce,C#,Audio,Windows Ce,我已经试着追踪了一段时间,但我不知道下一步该去哪里。无论何时调用waveOutPrepareHeader(),我都会得到invaliParams,指示“缓冲区的基址与样本大小不一致。” 我目前正在使用通过MSDN找到的方法从文件中的“数据”标记(和长度)后的数据中准备标头 public Wave.SystemError Read(BinaryReader rdr, uint readLength) { dwBufferLength = readLength;

我已经试着追踪了一段时间,但我不知道下一步该去哪里。无论何时调用waveOutPrepareHeader(),我都会得到invaliParams,指示“缓冲区的基址与样本大小不一致。”

我目前正在使用通过MSDN找到的方法从文件中的“数据”标记(和长度)后的数据中准备标头

    public Wave.SystemError Read(BinaryReader rdr, uint readLength)
    {
        dwBufferLength = readLength;
        byte[] data = new byte[readLength];
        rdr.Read(data, 0, data.Length);

        if (lpData == IntPtr.Zero)
            lpData = Memory.LocalAlloc(Memory.LMEM_FIXED,
               (uint)data.Length);

        if (lpData == IntPtr.Zero)
            return Wave.SystemError.NOMEM;

        Marshal.Copy(data, 0, lpData, data.Length);

        return Wave.SystemError.NOERROR;
    }
在对我得到的wave文件调用此函数之后,在使用之前,该类的所有参数都被调零

dwBufferLength = 32768
dwBytesRecorded = 0
dwFlags = 0
dwLoops = 0
dwUser = 0
lpData = 384656
lpNext = 0
reserved = 0
当传入

return waveOutPrepareHeader(hWaveOut, 
                            ref headerBuffer[buffIndex],
                            (uint)Marshal.SizeOf(headerBuffer[buffIndex]));
其中headerBuffer[buffIndex]是上述WAVEHDR,我得到11(MMSYSERR_INVALPARAM)。我已经检查过了,我的头型和尺码看起来都很正常,所以我不得不断定问题出在头球上,但我不知道是什么错了,甚至不知道该检查什么


我需要做什么来修复此错误,或者如果无法修复,我可以检查什么来查看导致此错误的原因?非常感谢您的帮助

您的样本大小是否大于1字节?如果是这样,那么

在ARM上,保持数据对齐很重要,所以如果您分配字节(一个字节)缓冲区,然后将其转换为短字节(两个字节),那么如果字节缓冲区分配在奇数地址上,那么您将获得未对齐的数据访问

所以,如果样本大小为两个字节,则必须确保字节缓冲区地址始终为偶数

为了验证这一点,您可以在出现错误时检查lpData的值,如果是奇数,则只需再分配1个字节,并将buffer+1发送给winapi函数


以下是正确对齐的示例代码,位于:


问题最终不是lpData(由LocalAlloc正确分配)的问题,而是WAVEHDR结构本身传递给PInvoked WaveOutprePrepreHeader的方式的问题

waveOut上的大多数材质(甚至对于C#)都会让您传入标题类型的对象。但为了停止获取错误,我必须使用Marshal.AllocHGlobal创建一个数据块,并使用Marshal.StructureToPtr将头复制到其中。然后,AllocHGlobal中的IntPtr被传递到WaveOutprePrePreHeader,从而解决了问题

这里有一些粗略的示例代码,供遇到类似问题的人使用

WAVEHDR header = new WAVEHDR();
//Read or setup header data here
IntPtr headerPtr = Marshal.AllocHGlobal(Marshal.SizeOf(header));
Marshal.StructureToPtr(header, headerPtr, true);
waveOutPrepareHeader(hWaveOut, headerPtr, (uint)Marshal.SizeOf(header));
这假设您将使用标头的所有内容的PInvoke设置为IntPtr类型,而不是WAVEHDR类型


从这里开始,将headerPtr用于需要传入该标题的所有位置。您必须按照预期在适当的位置自行处理内存释放。

您能指出一些有关
WavePrepareHeader
的文档吗?我所能找到的就是WaveInPrepreheader噢,这是对WaveOutprepreheader的一次反问。我将编辑我的问题,使之更清楚。这方面的文档就是新的信息。我试着将这段代码移植到非CE上,看看是否有什么不同,同一段代码(PInvokes指向的DLL交换除外)通过了WaveOutpreprepreheader,没有返回任何错误。我不确定这对问题的意义,但它似乎很有针对性。我用四字节块和两字节块的wave尝试了这段代码,但到目前为止,我所有的lpData都是偶数,并且可以被适当的块数整除。在C#中工作时,IntPtr是实际的内存地址吗?我不太做C#编程,我找到了示例代码:这可能会对您有所帮助,与您的代码不同的是,它在使用前对齐缓冲区长度。我将read()函数作为答案。不幸的是,尝试该代码最终会进行调整,因为32768%2、4、16和32(不确定align是位还是字节)都返回0是否尝试使用Marshal.AllocHGlobal?正如我所看到的,一切似乎都很好。AllocHGlobal最终成为了解决方案。在正确设置lpData变量的同时,我需要获取标头的实际结构,并将其放入一个数据块中,我通过Marshal.StructureToPtr使用指针,然后将其传递到waveOutPrepareHeader函数中。我将在稍后将所有这些编译成一个答案,供未来的问题寻求者使用,除非您愿意,这样您就可以从中获得要点。再次感谢您的帮助。
WAVEHDR header = new WAVEHDR();
//Read or setup header data here
IntPtr headerPtr = Marshal.AllocHGlobal(Marshal.SizeOf(header));
Marshal.StructureToPtr(header, headerPtr, true);
waveOutPrepareHeader(hWaveOut, headerPtr, (uint)Marshal.SizeOf(header));