mimikaireo
@mimikaireo

Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

【緊急】コマンドの結果を変数に格納して結果に応じて処理を変えたい

解決したいこと

外部から起動したコンソールアプリにいくつかのコマンドA,B,C,Dを投入して、コマンド show status pp2を投入するときだけ、その結果がエラー時に再度コマンド show status pp2を投入できるようにしたい
→現状:標準出力のリダイレクトを使って、投入結果を文字列の変数に格納、それをif文で結果に応じて処理する(にしようとしてる)

発生している問題・エラー

変数に結果が入らない。空っぽのまま
下記のコードを実行すると show status pp2コマンドを投入し、結果が表示されたあとに
Object reference not set to an instance of an object というメッセージが表示されます
VisualStudio Community 2022 17.4.2を使用しています

該当するソースコード

using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Collections;
using System.Collections.Generic;
using Microsoft.VisualBasic.ApplicationServices;
using System.Windows.Forms;
using static System.Windows.Forms.VisualStyles.VisualStyleElement;
using static System.Windows.Forms.VisualStyles.VisualStyleElement.Button;
using System.Runtime.InteropServices;
using Microsoft.VisualBasic;
using System.Reflection.PortableExecutable;
using static System.Windows.Forms.VisualStyles.VisualStyleElement.ToolBar;
using System.Text;

namespace hoge
{
    public partial class Form1 : Form
    {
        string output = ""; //コマンドDの結果を読み取るのに使う
        //----------省略----------------------------
        void TTprocess//コンソールアプリの起動・コマンド投入
        {

             int i;
             int iMax = 1;//失敗したときのまつ時間(分)
             int j = 0;//ダメだった時の繰り返す添え字
             int jMax = 3;
            var proc = new System.Diagnostics.Process();
            proc.StartInfo.FileName = "";//省略
            proc.StartInfo.RedirectStandardOutput = true;// 標準出力をリダイレクト
            proc.StartInfo.UseShellExecute = false;
            proc.OutputDataReceived += this.DataReceived;
            proc.StartInfo.RedirectStandardError= true;//エラー出力のリダイレクト

            Microsoft.VisualBasic.Interaction.AppActivate("省略");
            System.Threading.Thread.Sleep(3000); 
            proc.Start();
            proc.WaitForInputIdle();
            do
            {
             SendKeys.Send("show status pp2");
             proc.BeginOutputReadLine(); // 標準出力の読み取り(非同期) 
             //proc.WaitForExit(); 
                
            System.Threading.Thread.Sleep(3000);
            //TEST用
             //MessageBox.Show("output =" + output);
             //this.TopMost = true;
    
            //ここまでTEST用

            if (output.Contains("一度も") == false)//成功した
            {
                //----成功時の処理を行う(省略)-------------------------
                proc.CancelOutputRead();//標準出力の読み取り(非同期)停止
                break;
           }                
           else//失敗した
           {
                //成功しなかったときの処理がここにくる
                //---------------省略------------------
                for (i = 0; i < iMax; i++)
                {
                    System.Threading.Thread.Sleep(60000);//成功しなかったら60秒まつ
                }
          }

         j = j + 1;
         if (j == jMax)
         {
             MessageBox.Show("試行回数3回になりました");
             this.TopMost = true;
             break;
         }
             proc.CancelOutputRead();//標準出力の読み取り(非同期)停止
      } while (j < jMax);    
        Console.WriteLine($"process exit code: {proc.ExitCode}");//終了コードを出力する
    }// void TTprocess()のカッコ閉じ

        void DataReceived(object sender, DataReceivedEventArgs e)//イベントハンドラ
        {
            output = e.Data;
           // Console.WriteLine(output);            
            //output = e.Data;            
        }
        
        void func2()
        {
            //TTprocess()で起動したアプリへ別のコマンドを投入していく
            //コマンドE,F...
        }

        void ProcessEnd()//コンソールアプリとツールの終了
        {
             System.Diagnostics.Process[] aaa = System.Diagnostics.Process.GetProcessesByName("aaa(省略)");
                if (0 < aaa.Length)
                {
                    //見つかった時は、アクティブにしてアプリを終了
                    Microsoft.VisualBasic.Interaction.AppActivate("省略");
                    System.Threading.Thread.Sleep(1500);
                    SendKeys.Send("%q");
                }
                else
                {
                    //なんもしない
                }
                //このアプリケーションそのものを終了
                Console.Beep(1245, 300);
                Console.Beep(1319, 300);
                Console.Beep(1397, 300);
                Console.Beep(1480, 1000);
                System.Threading.Thread.Sleep(1000);
                Application.Exit();
        }

          private void button2_Click(object sender, EventArgs e)//コンソールアプリを起動・コマンド投入するボタン
        {
            TTprocess();            
        }

        private void button11_Click(object sender, EventArgs e)//終了ボタン
        {
            ProcessEnd();
        }
    }
}

自分で試したこと

調べたけと自分の知識がたりなくてよくわかりませんでした。
閲覧したサイト
https://takap-tech.com/entry/2017/07/08/151756
https://cammy.co.jp/technical/c_redirect/
https://atmarkit.itmedia.co.jp/ait/articles/0710/11/news123.html
https://www.fenet.jp/dotnet/column/language/9639/
https://biotech-lab.org/articles/10000
https://www.ipentec.com/document/csharp-get-standard-output-async
https://qiita.com/acple@github/items/8f63aacb13de9954c5da
https://learn.microsoft.com/ja-jp/dotnet/csharp/programming-guide/concepts/async/

0

3Answer

子プロセスからの出力はStandardErrorも確認してみてください.

また,プロセスが正常終了したか否かは出力メッセージではなく,終了コードを用いて判定するようにしてください.よほど作りの悪いCLIでなければ何か異常があった際に0以外のコードを返すはずです.

2Like

Comments

  1. @mimikaireo

    Questioner

    回答ありがとうございます。エラー出力・終了コードの内容も確認してみます。
  2. @mimikaireo

    Questioner

    エラー出力・終了コードの表示をつけ足してみましたが、上記のエラーメッセージが表示される状態になっています。エラーメッセージについて調べてみます。

下記のコードを実行すると show status pp2コマンドを投入し、結果が表示されたあとに
Object reference not set to an instance of an object というメッセージが表示されます

多分、NullReferenceException例外が発生していると思われますが、想定外の変数がnullになったりしていないですか?例外処理をしてExceptionオブジェクトの中身を調査してください。ExceptionオブジェクトのMessageで例外の内容、StackTraceで例外の発生元が判ります。

デバッグで任意の場所で一時停止させたり、一行づつ実行したり、リアルタイムで変数の値を確認することも出来ます。例外の発生個所を、まず特定してください。

1Like

Comments

  1. @mimikaireo

    Questioner

    回答ありがとうございます。リンク先を閲覧してみます。

Your answer might help someone💌