C#中的访问冲突 - winmm.dll ntdll.dll

时间:2011-04-13 21:00:34

标签: c# access-violation winmm

我有一个基本上做三件事的应用程序:

  1. 向用户显示图片
  2. 向用户播放1-2秒声音(wav)
  3. 录制麦克风输入4秒钟(播放声音时)
  4. 每个用户发生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());
            }
        }
    }
    

    请告诉我是否还有其他相关细节......

1 个答案:

答案 0 :(得分: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中的函数。正如其他人所说,你需要一个原生的堆栈跟踪来确切地看到发生了什么。

相关问题