2014-01-30 53 views
2

我需要播放聲音時點擊按鈕。我發現這是在C++中的DLL。所以我用p invoke,但一個錯誤彈出:PlaySound WinCE

錯誤2的最佳重載的方法匹配 'WinCE.Sound.PlaySound(字符串,System.IntPtr,INT)' 有一些無效 參數C:\用戶\ FERO \文檔\路由架錄像機\ WinCE的\ Sound.cs 44 17 WinCE的

而且也是這樣:

錯誤3參數 '3':無法從「WinCE.PlaySoundFlags轉換'到 'int'C:\ Users \ Fero \ Do cuments \ 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()); 
      } 
     } 
    } 
} 
+0

@ctacke這是一個純粹的P/Invoke問題,你不應該刪除那個標記 –

回答

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作爲它的基類型。

+0

非常感謝你的工作。 – franzp

+0

您是否在尋找更多幫助? –

+0

不是現在,但肯定晚些時候xD – franzp

1

它轉換成int這樣的:

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

而且,也不例外將永遠不會在P /調用一般異常。你需要檢查什麼函數返回,然後是Marshal.GetLastWin32Error()值,但在這種情況下,PlaySound不會在GetLastWin32Error中返回值。

+0

請不要在沒有更多注意的情況下建議使用'Marshal.GetLastWin32Error'。首先,你總是需要檢查「PlaySound」的返回值是否有錯誤。碰巧,這個函數不會調用SetLastError,所以你的建議是雙重錯誤的。 –

+0

不,不要調用'GetLastWin32Error()'。閱讀「PlaySound」的文檔。他們不會讓你調用GetLastError。並不是所有的Win32函數都會設置最後的錯誤值。這是這樣的。 –

+0

我投了反對票,因爲答案仍然顯示了一個關於錯誤處理的令人困惑的圖片。 Win32錯誤處理是一團糟,我認爲它應該得到非常精確的處理。如果您解決了問題,我會刪除投票。 –