1

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

  1. 向用户显示图像
  2. 向用户播放 1-2 秒的声音 (wav)
  3. 录制麦克风输入 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());
        }
    }
}

让我知道是否还有其他相关细节我应该包括...

4

1 回答 1

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 中的函数。正如其他人所说,您需要一个本机堆栈跟踪才能准确查看发生了什么。

于 2011-04-14T00:03:38.393 回答