1

C#2008 Windowsアプリケーションの実行が完了しないという問題があり、問題を解決する方法を決定しようとしています。当初、C#2010コンソールアプリケーションは、C#2008コンソールアプリケーションを呼び出すように作成されていました。C#2008コンソールアプリケーションは、Webサービスを呼び出します。dosポップアップウィンドウが欲しくないので、これらのアプリケーションを両方ともWindowsアプリケーションに変更しました。

問題は、呼び出されたC#2008Windowsアプリケーションが実行を終了しないことです。プロセスはメモリに残ります。

以下にリストされているコードは、C#2010アプリケーションのコードの一部です。

private static Logger logger = LogManager.GetCurrentClassLogger(); 
try
{
    Process eProcess = new Process();
    strConsoleAppLocation = ConfigurationManager.AppSettings["client_location"];
    String Process_Arguments = null;
    eRPT_Process.StartInfo.UseShellExecute = false;
    eRPT_Process.StartInfo.FileName = strConsoleAppLocation;
    Process_Arguments = " 1 CLI";
    eProcess.StartInfo.Arguments = Process_Arguments;
    eProcess.Start();
    eProcess.WaitForExit(1800);
    Process_Arguments = null;
    eProcess.StartInfo.UseShellExecute = false;
    Process_Arguments = " 2 TIM";
    eProcess.StartInfo.Arguments = Process_Arguments;
    eProcess.Start();
    eProcess.WaitForExit(1800);
    eProcess.Dispose();
    Process_Arguments = null;
}
catch (Exception e)
{
    logger.Error(e.Message + "\n" + e.StackTrace);
} 

C#2008アプリは、メモリ内のプロセスを調べても終了しないことを知っています。さらに、コード行を次のように変更するとeProcess.WaitForExit();、アプリケーションは呼び出されたプログラムに戻りません。

アプリケーションと呼ばれるC#2008では、実行されるコードの最後の行は次のとおりです。

Environment.Exit(1);   

したがって、この問題を解決するために、次の質問があります。

  1. 上記のコードを変更する方法についての推奨事項がある場合は、推奨事項を教えてください。

  2. これらの2つのプログラムは現在本番環境にあるので、「バンドエイド」修正のためにこの問題を解決する方法について提案がありますか?C#2010プログラムの実行が終了したときに実行中のC#2008プロセスを停止する方法はありますか?実行が終了したときにC#2008アプリケーションが独自のプロセスを強制終了する方法はありますか?もしそうなら、この問題を解決する方法のコードを教えてもらえますか?

  3. 長期的な修正について、C#2008プロセスが停止しない理由を特定する方法と、修正する方法を教えてください。私はプロファイラーを使用しますが、私の会社にはVisual Studio 2010のプロフェッショナルバージョンしかありません。それで、あなたの推奨事項を教えてください。

4

4 に答える 4

3

WaitForExit()つまり、待機しているプロセスが終了するのを無期限に待機しWaitForExit(int milliseconds)ますが、指定された期間待機してからタイムアウトします。

あなたが書いたことから、C# 2010 プログラムから起動している C# 2008 プログラムは決して終了しません。これにはいくつかの理由が考えられます。

  • ユーザーの入力を待っている可能性があります。

  • 無限ループに陥る可能性があります。

  • マルチスレッドの場合、スレッドの 1 つが実行を完了していない可能性があり、それがプロセスを維持しています (スレッドがバックグラウンド スレッドに設定されていない場合)。

コマンドラインから直接実行して、何をしているのかを確認してください。

C# 2008 プログラムの動作が、コマンド ラインから実行した場合は正しく、期待どおりであるが、C# 2010 プログラムから実行した場合は動作が異なる場合は、両方のシナリオで引数が一致することを確認します。

pskillを使用して、実行中のプロセスを強制終了できます。次のようなことができます:

if (!process.WaitForExit(1800))
{
    // launch a process for pskill to kill the C# 2008 program
}

最後に、C# ソリューション/プロジェクトを開き、Visual Studio のメニュー バー項目Attach to Processの下にあるコマンドを使用して、実行中のプログラムをデバッグできます。Debug

于 2013-02-16T11:04:21.093 に答える
0
  1. いいえ、コードに pskill を直接入力することはできません。System.Diagnostics.Process クラスを使用して、現在 C# 2008 プログラムで行っているのと同じように、プロセスを起動する必要があります。

  2. その通りです。プロジェクトが作成されたバージョンに関係なく、Visual Studio を使用してプロセスにアタッチします。プログラムのソリューションを開いたら、[ ] をクリックしDebug\Attach to Processます。マシンで実行中のプロセスのリストが表示されます。列の 1 つ (通常は最初の列) には、実行可能ファイルの名前が表示されます。これは、C# 2008 アプリケーションの名前と一致します。リストで C# 2008 プログラムを選択Attachし、疑わしいコード行にブレークポイントを配置した後、ボタンをクリックします。

  3. 私はあなたが何を意味するのか分かりません。

  4. デバッグは、何が起こっているのかを理解できる唯一の方法です。

あなたの質問を読み直して気付いた最後のこと。C# 2008 アプリケーションを Windows アプリケーションに変換しましたが、それでよろしいですか? それはあなたが望むものではありません。Windows アプリケーションは何らかの方法で終了する必要があり、対話が必要です。両方のアプリケーションをコンソール アプリケーションに戻してProcess、C# 2008 アプリケーションを起動するオブジェクトを作成するときに、パラメーターのCreateNoWindowプロパティをコンストラクターに true として設定する必要があります。ProcessStartInfoProcess

したがって、次のようなものです:

public class Processor
{
    private static Logger logger = LogManager.GetCurrentClassLogger();

    private ProcessStartInfo MakeProcessStartInfo(string fileName, string arguments)
    {
        return new ProcessStartInfo
        {
            CreateNoWindow = true,
            UseShellExecute = false,
            FileName = fileName,
            Arguments = appArguments
        };
    }

    public void CallExternalApplications()
    {
        try
        {
            var fileName = ConfigurationManager.AppSettings["client_location"];

            using (var process = new Process { StartInfo = MakeProcessStartInfo(fileName, " 1 CLI") })
            {
                process.Start();

                if (!process.WaitForExit(1800))
                {
                    // create a Process here for pskill to kill the "process" using process.Id.
                }
            }

            using (var process = new Process { StartInfo = MakeProcessStartInfo(fileName, " 2 TIM") })
            {
                process.Start();

                if (!process.WaitForExit(1800))
                {
                    // create a Process here for pskill to kill the "process" using process.Id.
                }
            }
        }
        catch (Exception e)
        {
            // you really should be using logger.ErrorException(e.Message, e) here
            // and be using the ${exception} layoutrenderer in the layout in the NLog.config file
            logger.Error(e.Message + "\n" + e.StackTrace);
        }
    }
}

オブジェクトを作成するコードを繰り返しているため、おそらくこのコードをさらにリファクタリングできprocessます。ブロックを使用して、オブジェクトusingの を暗黙的に呼び出しました。これにより、コードがよりクリーンで読みやすくなります。Disposeprocess

重要なCreateNoWindowのはオブジェクトのプロパティを設定するProcessStartInfoことです。これにより、アプリケーションを Windows アプリケーションからコンソール アプリケーションに戻すと、コンソール ウィンドウのポップアップが停止します。

于 2013-02-16T23:13:29.237 に答える