I have an application which basically does three things:
- Show an image to the user
- Play a 1-2 second sound (wav) to the user
- Record microphone input for 4 seconds (while sound is playing)
This happens 280 times per user, and all of the recordings are saved in a directory for each user. However, 2 out of the last 18 runs of the program, it crashed from an unhandled exception with code c0000005 (which is described as an access violation) in module ntdll.dll. The only unmanaged api call I'm using is mciSendString from winmm.dll to get the duration of wav files and do the recording. Playback is done using an instance of WindowsMediaPlayer.
The crashes seem to be random, and both happened on the same machine (3 are being used). These are my questions: Is ntdll.dll really the source of the exception? Am I correct in understanding the access violation is an invalid memory access? And how could that happen with a C# program running in the .NET virtual machine?
By request here is one class from which I invoke 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(""))
{
tryMCISend开发者_如何学PythonString("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());
}
}
}
Let me know if there are other relevant details I should include...
One problem is this:
private static extern uint mciSendString(string lpstrCommand,
string lpstrReturnString, int uReturnLength, int hwndCallback);
That last value should be IntPtr
. Otherwise it's not going to work in the 64-bit runtime and it's possible that something could step on the stack. Change that to IntPtr
and pass `IntPtr.Zero'.
Also, the lpstrReturnString
parameter is there for you to pass a pointer to a buffer that will receive returned data. Passing an empty string here is a bad idea, because mciReturnString
might try to store data in that string. That could give you an access violation or, worse, overwrite something critical. If you don't need error information returned, then either change that to IntPtr
and pass IntPtr.Zero
, or use a StringBuilder
. See http://www.pinvoke.net/default.aspx/winmm.mcisendstring for the correct definition.
And, yes, it makes perfect sense for ntdll.dll to be the source of the exception, since it's likely that the functions in winmm.dll call functions that are in ntdll.dll. As others have said, you'll need a native stack trace to see exactly what's happening.
精彩评论