2011-04-13 74 views
0

我有一個應用程序,它基本上是做了三兩件事:訪問衝突 - WINMM.DLL ntdll.dll中

  1. 顯示給用戶
  2. 播放1-2秒的聲音(WAV)的圖像4秒用戶
  3. 記錄麥克風輸入(當播放聲音時)

這發生每個用戶280倍,並且所有的記錄的保存在每個用戶的目錄。但是,程序的最後18次運行中有2次,它在模塊ntdll.dll中從代碼爲c0000005(描述爲訪問衝突)的未處理異常中崩潰。我使用的唯一非託管API調用是winmm.dll中的mciSendString來獲取wav文件的持續時間並進行錄製。回放是使用WindowsMediaPlayer的一個實例完成的。

崩潰似乎是隨機的,並且都發生在同一臺機器上(正在使用3臺)。這些是我的問題:ntdll.dll真的是異常的來源?我正確理解訪問衝突是無效的內存訪問嗎?那在.NET虛擬機中運行的C#程序怎麼會發生這種情況呢?

通過要求在這裏是一個類從我調用mciSendString

public class JE_SR 
{ 
    [DllImport("winmm.dll", EntryPoint = "mciSendStringA", 
     CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)] 
    private static extern uint mciSendString(string lpstrCommand, 
     string lpstrReturnString, int uReturnLength, int hwndCallback); 

    [DllImport("winmm.dll", CharSet = CharSet.Auto)] 
    private static extern int mciGetErrorString(uint errorCode, 
     StringBuilder errorText, int errorTextSize); 


    private static bool recording = false; 
    public static uint lastResult; 

    public static void startRecording() 
    { 
     if (recording) 
     { 
      return; 
     } 

     tryMCISendString("open new Type waveaudio Alias recsound", "", 0, 0); 
     tryMCISendString("record recsound", "", 0, 0); 

     recording = true; 
    } 

    public static void stopRecording(string file) 
    { 
     if (!recording) 
     { 
      return; 
     } 

     if (!file.Equals("")) 
     { 
      tryMCISendString("save recsound " + file, "", 0, 0); 
      tryMCISendString("close recsound ", "", 0, 0); 
     } 
     else 
     { 
      tryMCISendString("close all", "", 0, 0); 
     } 

     recording = false; 
    } 

    public static void tryMCISendString(string lpstrCommand, 
     string lpstrReturnString, int uReturnLength, int hwndCallback) 
    { 
     lastResult = mciSendString(lpstrCommand, lpstrReturnString, uReturnLength, hwndCallback); 

     StringBuilder error = new StringBuilder(256); 
     if(lastResult != 0) 
     { 
      mciGetErrorString(lastResult, error, error.Length); 
      JE_Log.logMessage("MCIERROR(JE_SR): " + error.ToString()); 
     } 
    } 
} 

讓我知道,如果有其他相關細節,我應該包括...

+0

您定義P/Invoke簽名的方式以及您調用方式的源代碼可能會有所幫助。 – 2011-04-13 21:03:06

+3

如果代碼正在執行P/Invoke,則不能確定該程序正在.NET虛擬機中運行(僅限於)。這就像說:「當他入獄時(囚犯打開門),囚犯怎麼會這樣做」 – 2011-04-13 21:03:30

+0

在我們弄清楚發生了什麼事之前,我們需要一個* native * call stack。爲了得到這個,下載Debugging Tools for Windows,運行WinDbg,「Attach to Process」,然後輸入'.symfix; kn100'進入命令窗口 – 2011-04-13 21:11:12

回答

2

的一個問題是這樣的:

private static extern uint mciSendString(string lpstrCommand, 
     string lpstrReturnString, int uReturnLength, int hwndCallback); 

最後一個值應該是IntPtr。否則,它不會在64位運行時中工作,並且有可能會有一些東西進入堆棧。將其更改爲IntPtr並傳入`IntPtr.Zero'。

此外,lpstrReturnString參數是在那裏爲您傳遞指針到緩衝區,將接收返回的數據。在這裏傳遞一個空字符串是個不錯的主意,因爲mciReturnString可能會嘗試在該字符串中存儲數據。這可能會導致訪問違規,或者更糟糕的是,會覆蓋重要的內容。如果您不需要返回錯誤信息,則將其更改爲IntPtr並通過IntPtr.Zero或使用StringBuilder。正確的定義見http://www.pinvoke.net/default.aspx/winmm.mcisendstring

而且,是的,它對ntdll.dll成爲異常的來源非常有意義,因爲它很可能是winmm.dll中的函數調用ntdll.dll中的函數。正如其他人所說的那樣,您需要一個本地堆棧跟蹤來查看到底發生了什麼。

+0

所以我知道這是多年後,但我只想告訴你,這是我在我使用的庫中的確切問題,現在我終於可以使用它.Net Framework 4+。出於某種原因,我被限制在3.5之前。非常感謝! ^^ – Falgantil 2015-07-04 18:50:46