[英]C#: How can I open a process, wait until the program in the process loads completely, and then use a new process to execute commands?
對於 C#,我需要打開一個程序,等到該程序完全加載,然后我想運行 cmd.exe 來運行其他命令來操作該程序的原始實例。
我試圖讓一個名為 GerbView 的特定程序以某種方式運行。 該程序用於查看 Gerber 文件,PCB 制造商用來蝕刻 PCB 的文件。 該程序可以使用自己的打開命令在內部加載 Gerber 文件。 然而,我的程序是為了處理其中一些 Gerber 文件,然后使用 GerbView 加載這些處理過的 Gerber 文件。 我能夠完成此任務的唯一方法是通過命令行界面。 可以打開 Gerber 文件的命令是gerbview {filename} 。
我知道進程 class 可以使用 FileName 和 Arguments 屬性輕松完成此操作,但我需要向同一實例添加更多文件。 執行此操作的命令是gerbview /add {filename} 。
最后一條命令將啟動程序,如果一個實例已經打開,它只會添加一個額外的文件以供查看。 現在這是我遇到問題的地方。 在我提出最終解決方案(見下文)之前,我的程序一直打開多個實例(盡管使用了/add參數),這可能是因為在執行/add arguments 的 rest 時程序尚未准備好輸入。 只有當我添加 1 秒延遲時,代碼才能正確運行。 但是,當我通過 Microsoft Teams 向某人展示時,舊行為又回來了,直到我增加了延遲(我假設 Teams 廣播導致需要更大的延遲)。 以下是我目前的解決方案(該程序是 windows 表格的一部分):
Process gerbView;
Process cmd;
bool gerbViewActive;
// The is the windows form constructor
public WindowsFormGUI()
{
InitializeComponent();
gerbViewActive = false;
}
private void buttonRunProgram_Click(object sender, EventArgs e)
{
OpenFileDialog loadFiles = new OpenFileDialog
{
Multiselect = true,
InitialDirectory = Directory.GetParent(Directory.GetCurrentDirectory()).FullName
};
if (loadFiles.ShowDialog() == DialogResult.OK)
{
if (!gerbViewActive)
{
gerbView = new Process();
gerbView.EnableRaisingEvents = true;
gerbView.Exited += new EventHandler(GerbView_Exited);
gerbView.StartInfo.FileName = @"C:\Program Files\Software Companions\GerbView\gerbview.exe";
gerbView.StartInfo.WindowStyle = ProcessWindowStyle.Maximized;
gerbView.Start();
gerbViewActive = true;
}
// wait until GerbView loads before running the cmd process.
Thread.Sleep(2000);
string[] files = loadFiles.FileNames;
cmd = new Process();
cmd.StartInfo.FileName = "cmd.exe";
cmd.StartInfo.RedirectStandardInput = true;
cmd.StartInfo.UseShellExecute = false;
cmd.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
cmd.StartInfo.WorkingDirectory = @"C:\Program Files\Software Companions\GerbView\";
cmd.Start();
using (StreamWriter cmdInput = cmd.StandardInput)
{
for (int index = 0; index < files.Length; index++)
{
cmdInput.WriteLine("gerbview.exe /add " + files[index]);
}
}
cmd.Close();
}
}
private void GerbView_Exited(object sender, EventArgs e)
{
gerbViewActive = false;
gerbView.Close();
}
任何幫助或建議將不勝感激。
首先,您正在執行的命令行工具必須嘗試定位現有進程並與之通信。 我會跳過運行cmd.exe
,而只是自己運行每個gerbview.exe /add
進程。 然后你可以.WaitForExit()
來確保每個進程在開始另一個進程之前已經完成。 然而,這可能還不夠。
接下來,您需要在主 UI 進程上使用.WaitForInputIdle()
進行阻塞,直到主線程清除了它的 win32 事件隊列。 這很可能是他們的文件打開命令行能夠與之成功通信的必要條件。
明確地說,您需要的最少步驟是;
由於您正在啟動與主 UI 相同的查看器可執行文件並打開每個文件,因此它很可能是“windows 子系統”可執行文件而不是控制台可執行文件。 cmd.exe 將啟動進程,但在退出之前不會阻塞。 確定它已退出的唯一方法是自己啟動該過程。
您還可以嘗試向查看器進程的 window 句柄發布或發送一些 noop window 消息,以確保.WaitForInputIdle 有一些新的輸入要等待。
這些都不能保證這個過程會起作用。 這完全取決於這個第 3 方應用程序的編寫方式。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.