C# 使用 Process.Start 執行外部程式
C# 執行外部程式的方式並不難,也很簡單,首先引入
using System.Diagnostics;然後使用 Process.Start("OtherProgram.exe")方式就可以呼叫並執行。
但是,某些情況下會導致程式無法被執行(或是無法正常執行),
很多原因在於『執行程式的起始位置』,由於被呼叫的程式執行時,
它所啟動的路徑其實是在呼叫程式的路徑下,
如果被呼叫程式需要讀取與程式相同路徑下的文件檔案(或是INI),可能會導致找不到的問題。
為了測試這樣的現象,我準備了2支程式,
一支是被呼叫端的程式 HelloConsole.exe
另外一支就是呼叫端程式 CallOtherProgram.exe
HelloConsole.exe 這支程式在啟動時會讀取相同路徑下的 Doc.txt 並將內容顯示出來,如果有參數也會把參數列出來。而這支程式我固定放在 D:\TEST\ 下,以方便測試,如果不是在這路徑下,那呼叫端的程式碼裡面的路徑也要變更。
HelloConsole.exe
using System;
using System.IO;
namespace HelloConsole
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("This is HelloConsole.exe");
Console.WriteLine(" ");
Console.WriteLine("Environment.CurrentDirectory is ");
Console.WriteLine(Environment.CurrentDirectory);
Console.WriteLine(" ");
Console.WriteLine("AppDomain.CurrentDomain.BaseDirectory is ");
Console.WriteLine(AppDomain.CurrentDomain.BaseDirectory);
Console.WriteLine(" ");
if (args.Length > 0)
{
Console.WriteLine("You passed arguments is :");
foreach(string arg in args)
{
Console.WriteLine(arg);
}
}
string fileName = "Doc.txt";
if (File.Exists(fileName))
{
Console.WriteLine("Retrieve Doc.txt content ...");
using (StreamReader reader = new StreamReader(fileName))
{
string content = reader.ReadToEnd();
Console.WriteLine("===== Start of content =====");
Console.WriteLine(content);
Console.WriteLine("====== End of content ======");
}
}
else
{
Console.WriteLine(" >> Doc.txt can not be read because it not exists !!");
}
Console.WriteLine(" ");
Console.Write("Press Enter to Close Program....");
Console.ReadLine();
}
}
}
另外 Doc.txt 內容:
1.This is a document file with program and in same folder
2.Use to test program can read text normal.
注意上面程式碼開啟 Doc.txt 的方式是不帶絕對路徑的方式,意思是希望以程式當下啟動路徑下直接開啟 Doc.txt。(下面會解釋呼叫會發生的問題)
我們先單獨執行 HelloConsole.exe 看看是甚麼樣子
從畫面可以發現執行後 Environment.CurrentDirectory 這樣的環境變數確實是在程式存在的地方(D:\TEST),因此讀取/開啟 Doc.txt 時可以正常讀取。
- 簡單呼叫方式
- 簡單呼叫方式(帶參數)
- 標準呼叫方式(提供環境設定)
- 標準呼叫方式(提供環境設定/帶參數)
CallOtherProgram.exe
using System;
using System.Diagnostics;
using System.IO;
namespace CallOtherProgram
{
class Program
{
static void Main(string[] args)
{
string fileName = "D:\\TEST\\HelloConsole.exe";
Console.WriteLine("This Program use to test call other program by different method ,");
Console.WriteLine("It will call " + fileName + " to run and watch it execute result");
Console.WriteLine(" ");
Console.WriteLine("1.Default call(no change path)");
Console.WriteLine("2.Default call with argument string");
Console.WriteLine("3.Change execution environment path");
Console.WriteLine("4.Change execution environment path with argument string");
Console.Write("\r\n >> ");
var key = Console.ReadKey(true);
if (key.KeyChar == '1')
{
//第一種
Process.Start(fileName);
}
else if(key.KeyChar == '2')
{
//第二種
Console.WriteLine("\r\n Input string (separated by space cahracter and Enter to be end): ");
Console.Write("\r\n >> ");
string argStr = Console.ReadLine();
Process.Start(fileName, argStr);
}
else if (key.KeyChar == '3')
{
//第三種
string path = Path.GetDirectoryName(fileName);
string file = Path.GetFileName(fileName);
var startInfo = new ProcessStartInfo();
startInfo.WorkingDirectory = path;
startInfo.FileName = file;
Process.Start(startInfo);
}
else if (key.KeyChar == '4')
{
//第四種
Console.WriteLine("\r\n Input string (separated by space cahracter and Enter to be end): ");
Console.Write("\r\n >> ");
string argStr = Console.ReadLine();
string path = Path.GetDirectoryName(fileName);
string file = Path.GetFileName(fileName);
var startInfo = new ProcessStartInfo();
startInfo.WorkingDirectory = path;
startInfo.FileName = file;
startInfo.Arguments = argStr;
Process.Start(startInfo);
}
Console.WriteLine(" ");
Console.WriteLine("Press Enter to Close ....");
Console.ReadLine();
}
}
}
※其實上面一堆 Console.WriteLine 是可以簡化啦,只是懶惰了點都是搞複製/貼上所以才這麼多.....
執行結果:
第一種,基本用法 Process.Start(fileName),不帶參數,直接呼叫執行檔。
可以看到,被呼叫的 HelloConsole.exe 無法讀到跟它放在一起的 Doc.txt,從觀察中不難發現 HelloConsole.exe 的 Environment.CurrentDirectory 卻出現了 D:\MYAPP ??
也就是說 HelloConsole.exe 的執行環境變成呼叫者 CallOtherProgram.exe 的執行環境了。
第二種,基本用法的延伸,附帶參數 Process.Start(fileName, argStr) ,看得出來狀況跟第一種相同,無法讀取 Doc.txt ,但卻可以正確接收到參數傳入。
第三種,使用 ProcessStartInfo 傳入相關的參數值給 Process.Start
Process.Start(startInfo),利用這種方式要求 Process 建立自己的環境位置,
有了 startInfo.WorkingDirectory = path 這樣的設置,可以讓 HelloConsole.exe 在指定的路徑下被執行,因此可以正確讓 HelloConsole.exe 找到 Doc.txt 並顯示。
第四種,把第三種呼叫加入傳遞參數,當然這參數不適合使用第二種方法呼叫,而是把參數設定在 startInfo.Arguments 裡面,再以 Process.Start(startInfo) 方式執行,這樣 HelloConsole.exe 可以正確讀取 Doc.txt ,並且可以接收參數。
當然,最好處理方式是在 HelloConsole.exe 裡面讀取 Doc.txt 指定位置,當然可以使用 AppDomain.CurrentDomain.BaseDirectory 來強制取得執行程式路徑,只是實際使用時,可能也有需要在呼叫端的路徑下處理檔案。
只能說,程式寫法很自由,使用上要很小心,先確認開發的程式可能的執行方式,包含被呼叫執行(像是 Windows 工作排程就是一種呼叫端程式)的狀況下,也能正確執行,才是上上策。
留言