1

基本的に次の 3 つのことを行うアプリケーションがあります。

  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 を呼び出すクラスの 1 つを次に示します。

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

1つの問題はこれです:

private static extern uint mciSendString(string lpstrCommand, 
        string lpstrReturnString, int uReturnLength, int hwndCallback);

その最後の値はIntPtr. そうしないと、64 ビット ランタイムで機能せず、何かがスタックを踏む可能性があります。これをに変更してIntPtr、'IntPtr.Zero' を渡します。

また、lpstrReturnString返されたデータを受け取るバッファへのポインタを渡すためのパラメータもあります。mciReturnStringここで空の文字列を渡すのは、その文字列にデータを格納しようとする可能性があるため、悪い考えです。これにより、アクセス違反が発生したり、さらに悪いことに、重要なものが上書きされたりする可能性があります。エラー情報を返す必要がない場合は、これをIntPtrand passIntPtr.Zeroに変更するか、StringBuilder. 正しい定義については、http://www.pinvoke.net/default.aspx/winmm.mcisendstringを参照してください。

そして、もちろん、ntdll.dll が例外のソースであることは完全に理にかなっています。なぜなら、winmm.dll 内の関数が ntdll.dll 内の関数を呼び出す可能性が高いからです。他の人が言ったように、何が起こっているのかを正確に確認するには、ネイティブ スタック トレースが必要です。

于 2011-04-14T00:03:38.393 に答える