C# 播放声音畏缩

C# 播放声音畏缩,c#,compact-framework,pinvoke,windows-ce,C#,Compact Framework,Pinvoke,Windows Ce,我需要在点击按钮时播放声音。我找到了这个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:\

我需要在点击按钮时播放声音。我找到了这个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());
            }
        }
    }
}

将其转换为int,如下所示:

PlaySound(fileName, IntPtr.Zero, (int)(PlaySoundFlags.SND_FILENAME | PlaySoundFlags.SND_SYNC));
[DllImport("winmm.dll")]
public static extern bool PlaySound(
    string szSound,
    IntPtr hModule,
    PlaySoundFlags flags
);

此外,通常不会在p/Invokes上引发任何异常。您需要检查函数返回的内容,然后检查
封送.GetLastWin32Error()
值,但在本例中,PlaySound不会在GetLastWin32Error中返回值。

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

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

声明返回类型为<代码>布尔O/COD>比较容易,这是C++ >代码> BoOL >的更好匹配。

最后,在麻烦地声明了这个漂亮的枚举之后,您还可以在p/invoke中使用它。这样把它放在一起:

PlaySound(fileName, IntPtr.Zero, (int)(PlaySoundFlags.SND_FILENAME | PlaySoundFlags.SND_SYNC));
[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
作为其基类型。

请不要建议使用
Marshal.GetLastWin32Error
,不要太在意。首先,您总是需要检查
PlaySound
的返回值是否存在错误。碰巧,此函数不调用
SetLastError
,因此您的建议是错误的。不,不要调用
GetLastWin32Error()
。阅读
PlaySound
的文档。他们不会告诉您调用
GetLastError
。并非所有Win32函数都设置最后一个错误值。这就是其中之一。我投了反对票,因为答案仍然呈现出关于错误处理的混乱画面。Win32错误处理是一团糟,在我看来,它值得非常精确的处理。如果你修改了答案,我将删除否决票。你是否在寻求更多帮助?@ctacke这是一个纯粹的P/Invoke问题,你不应该删除该标记