Нарушение доступа в C # — winmm.dll ntdll.dll

#c# #access-violation #winmm

#c# #нарушение доступа #winmm

Вопрос:

У меня есть приложение, которое в основном выполняет три вещи:

  1. Показывать изображение пользователю
  2. Воспроизведение 1-2-секундного звука (wav) для пользователя
  3. Запись микрофонного ввода в течение 4 секунд (во время воспроизведения звука)

Это происходит 280 раз для каждого пользователя, и все записи сохраняются в каталоге для каждого пользователя. Однако в 2 из последних 18 запусков программы произошел сбой из-за необработанного исключения с кодом c0000005 (которое описывается как нарушение доступа) в модуле ntdll.dll . Единственный неуправляемый вызов API, который я использую, — это mciSendString из winmm.dll чтобы получить длительность файлов wav и выполнить запись. Воспроизведение выполняется с использованием экземпляра WindowsMediaPlayer.

Сбои кажутся случайными, и оба произошли на одном компьютере (используются 3). Это мои вопросы: является ли ntdll.dll действительно является источником исключения? Правильно ли я понимаю, что нарушение доступа — это недопустимый доступ к памяти? И как это могло произойти с программой на 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 lastResu<

    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. Исходный код того, как вы определили сигнатуру P / Invoke, и способ, которым вы ее вызываете, может быть полезен.

2. Если код выполняет P / Invoke, вы не можете действительно сказать, что программа запущена в . СЕТЕВАЯ виртуальная машина (только). Это все равно что сказать: «Как заключенный может это сделать, когда он в тюрьме (с открытой дверью)»

3. Нам нужен собственный стек вызовов, прежде чем мы сможем выяснить, что происходит. Чтобы получить это, загрузите средства отладки для Windows, запустите WinDbg, «Присоединить к процессу», затем введите ‘.symfix; kn100’ в окне командной строки

4. Несмотря на точность, печальной частью было сравнение .NET-программы с заключенным…

5. @Lasse Я знаю, что это выполняется не ТОЛЬКО на виртуальной машине. Меня сбил с толку тот факт, что в системном журнале указано, что причина исключения возникла из ntdll.dll , что восходит к моему первому вопросу: разумно ли мне вообще думать, что мое использование winmm.dll в чем причина?

Ответ №1:

Одна из проблем заключается в следующем:

 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 . Как уже говорили другие, вам понадобится встроенная трассировка стека, чтобы точно видеть, что происходит.

Комментарии:

1. Итак, я знаю, что это произошло много лет спустя, но я просто хочу сказать вам, что именно эта проблема, как выяснилось, была у меня в библиотеке, которой я пользовался, и теперь я наконец могу использовать ее с .Net Framework 4 . Раньше я по какой-то причине был ограничен 3.5. Большое вам спасибо! ^^