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

C#-winmm.dll ntdll.dll中的访问冲突,c#,access-violation,winmm,C#,Access Violation,Winmm,我有一个应用程序,它基本上做三件事: 向用户显示图像 向用户播放1-2秒的声音(wav) 录制麦克风输入4秒钟(声音播放时) 每个用户都会发生280次这种情况,所有录制都保存在每个用户的目录中。然而,在程序的最后18次运行中,有2次由于模块ntdll.dll中代码为c0000005(称为访问冲突)的未处理异常而崩溃。我使用的唯一非托管api调用是winmm.dll中的mciSendString,用于获取wav文件的持续时间并进行录制。播放是使用WindowsMediaPlayer实例完成的 这些

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

  • 向用户显示图像
  • 向用户播放1-2秒的声音(wav)
  • 录制麦克风输入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());
            }
        }
    }
    
    让我知道是否还有其他相关的细节我应该包括…

    一个问题是:

    private static extern uint mciSendString(string lpstrCommand, 
            string lpstrReturnString, int uReturnLength, int hwndCallback);
    
    最后一个值应该是
    IntPtr
    。否则,它将无法在64位运行时中工作,并且可能有什么东西会踩到堆栈上。将其更改为
    IntPtr
    并传递'IntPtr.Zero'

    另外,
    lpstrReturnString
    参数用于向接收返回数据的缓冲区传递指针。在这里传递一个空字符串是个坏主意,因为
    mciReturnString
    可能会尝试在该字符串中存储数据。这可能会导致访问冲突,或者更糟的是,覆盖一些关键内容。如果不需要返回错误信息,请将其更改为
    IntPtr
    并传递
    IntPtr.Zero
    ,或者使用
    StringBuilder
    。有关正确的定义,请参见


    而且,是的,将ntdll.dll作为异常源非常有意义,因为winmm.dll中的函数很可能调用ntdll.dll中的函数。正如其他人所说,您需要一个本机堆栈跟踪来准确查看发生了什么。

    关于您定义p/Invoke签名的方式和调用它的方式的源代码可能会有所帮助。如果代码是在执行p/Invoke,您就不能说程序正在.NET虚拟机中运行(仅限于)。这就像说“囚犯在监狱里(门开着)怎么能这样做”我们需要一个本地调用堆栈,然后才能知道发生了什么。要获得此信息,请下载Windows调试工具,运行WinDbg,“附加到进程”,然后键入“.symfix”;kn100'进入命令窗口虽然准确,但令人伤心的是将.NET程序与囚犯进行比较…@Lasse我知道它不仅仅在虚拟机中运行。让我感到不安的是,系统日志说异常的原因来自ntdll.dll,这又回到了我的第一个问题:我认为使用winmm.dll是原因是明智的吗?所以我知道这是多年以后的事了,但我只想告诉你,这正是我在使用的库中发现的问题,现在我终于可以将它与.NETFramework4+一起使用了。之前我因为某种原因被限制在3.5。非常感谢你^^