【问题标题】:PlaySound WinCE播放声音 WinCE
【发布时间】:2014-01-30 16:53:37
【问题描述】:

点击按钮时我需要播放声音。我找到了这个 C++ 中的 dll。所以我用p invoke,但是弹出一个错误:

错误 2 最好的重载方法匹配 'WinCE.Sound.PlaySound(string, System.IntPtr, int)' 有一些无效 参数 C:\Users\Fero\Documents\route-loader-recorder\WinCE\Sound.cs 44 17 WinCE

还有这个:

错误 3 参数“3”:无法从“WinCE.PlaySoundFlags”转换为 'int' C:\Users\Fero\Documents\route-loader-recorder\WinCE\Sound.cs 44 51 WinCE

有什么想法吗?

我的代码是:

namespace Sound
{
    public enum PlaySoundFlags : int {
        SND_SYNC = 0x0,     // play synchronously (default)
        SND_ASYNC = 0x1,    // play asynchronously
        SND_NODEFAULT = 0x2,    // silence (!default) if sound not found
        SND_MEMORY = 0x4,       // pszSound points to a memory file
        SND_LOOP = 0x8,     // loop the sound until next sndPlaySound
        SND_NOSTOP = 0x10,      // don't stop any currently playing sound
        SND_NOWAIT = 0x2000,    // don't wait if the driver is busy
        SND_ALIAS = 0x10000,    // name is a registry alias
        SND_ALIAS_ID = 0x110000,// alias is a predefined ID
        SND_FILENAME = 0x20000, // name is file name
        SND_RESOURCE = 0x40004, // name is resource name or atom
    };

    public class Sound
    {
        [DllImport("winmm.dll", SetLastError = true)]
        public static extern int PlaySound(
            string szSound,
            IntPtr hModule,
            int flags);

        public static void Beep() {
            Play(@"\Windows\Voicbeep");
        }

        public static void Play(string fileName) {
            try {
                PlaySound(fileName, IntPtr.Zero, (PlaySoundFlags.SND_FILENAME | PlaySoundFlags.SND_SYNC));
            } catch (Exception ex) {
                MessageBox.Show("Can't play sound file. " + ex.ToString());
            }
        }
    }
}

【问题讨论】:

  • @ctacke 这是一个纯粹的 P/Invoke 问题,您不应该删除该标签

标签: c# compact-framework pinvoke windows-ce


【解决方案1】:

您对PlaySound 的声明在很多方面都是错误的。

首先,不要将SetLastError设置为truePlaySound 的文档没有提到GetLastError,这意味着PlaySound 没有承诺调用SetLastError。它唯一的错误报告是通过它的返回值。

将返回类型声明为bool 更容易,这更适合C++ BOOL

最后,在声明了那个漂亮的枚举之后,你不妨在你的 p/invoke 中使用它。像这样放在一起:

[DllImport("winmm.dll")]
public static extern bool PlaySound(
    string szSound,
    IntPtr hModule,
    PlaySoundFlags flags
);

还要注意 Win32 API 函数不会引发异常。这些 API 函数专为互操作而设计,并非所有语言都支持 SEH 异常处理。所以它不会抛出,并且仅通过布尔返回值指示错误。

您的调用代码应该是:

public static void Play(string fileName) 
{
    if (!PlaySound(fileName, IntPtr.Zero,
        PlaySoundFlags.SND_FILENAME | PlaySoundFlags.SND_SYNC))
    {
        MessageBox.Show("Can't play sound file.");
    }
}

注意PlaySound 的最后一个参数的类型为DWORD。这是一个无符号的 32 位整数,所以严格来说你的枚举应该使用 uint 作为它的基本类型。

【讨论】:

  • 您需要更多帮助吗?
【解决方案2】:

像这样将它转换为 int:

PlaySound(fileName, IntPtr.Zero, (int)(PlaySoundFlags.SND_FILENAME | PlaySoundFlags.SND_SYNC));

此外,通常不会在 P/Invokes 上引发异常。您需要检查返回什么函数,然后检查 Marshal.GetLastWin32Error() 值,但在这种情况下,PlaySound 不会在 GetLastWin32Error 中返回值。

【讨论】:

  • 请不要不小心就使用Marshal.GetLastWin32Error。首先,您总是需要检查PlaySound 的返回值是否有错误。碰巧,这个函数没有调用SetLastError,所以你的建议是双重错误的。
  • 不,不要打电话给GetLastWin32Error()。阅读PlaySound 的文档。他们不会告诉你打电话给GetLastError。并非所有 Win32 函数都设置最后一个错误值。这就是其中之一。
  • 我投了反对票,因为答案在错误处理方面仍然令人困惑。 Win32 错误处理是一团糟,在我看来,它应该得到非常精确的处理。如果您修复答案,我将删除反对票。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多