2011-04-13 73 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