2013年3月18日 星期一

Windows 排程無法執行


用 .net 的 console 模式寫了一個 .exe 檔,在自己電腦上直接執行,是正常的,主要功能是讀取同個資料夾下面的 xml 檔,並進行後面的一些處理工作。但奇怪的是,當我使用電腦排程去呼叫 .exe 檔時,就會在排程表裡面發現所建立的排程一直處於「執行中」的狀態,且這個現象一直都不會停止,由於我是設成每天都要執行,所以當第二天的同個時間要執行時,就會出現錯誤,理由是先前的工作尚未結束,所以無法再做新的。這理由我倒覺得合理,但問題是,為何第一天執行的程式遲遲無法結束呢?心裡第一個念頭,是該不會在裡面給我跑無限迴圈吧!!

就在自己含淚一行一行的檢查程式之餘,發現原來程式是停在下面這一行:


System.Console.ReadLine();


原先是我用來判斷是否使用者有正確的擺放 xml 檔到執行程式的資料夾,沒有的話就會跳出訊息,並將執行畫面暫停,等待輸入「Enter」鍵之後再繼續執行。只是這作法,放到 windows 排程裡,就會造成系統為了要等待輸入「Enter」而停在那一直無法結束,其實程式不是在跑無限迴圈,而是無限等待


然而,真正產生問題的原因,並不只是因為自己誤用了 ReadLine()而已,最主要的問題是為何會找不到 xml 檔呢,我用我的兩隻眼睛的確在執行檔的資料夾下面都有看到啊。在網路上有看到許多人在討論 windows 排程無法正常執行的討論議題,其中「Windows server 2008 排程無法執行」這一篇有提到,如果有對檔案進行存取動作時,要使用完整路徑,否則他可能預設會用 C:\Windows\System32 資料夾來處理。我測試了一下,的確如此,假設我是直接去執行 .exe 檔,則他就會以執行檔所在路徑來處理,但使用排程時,就變成 C:\Windows\System32 了。

我在程式裡面有使用到

DataSet dsConfig=new DataSet();
string strFileName="setup.xml";
if(System.IO.File.Exists(strFileName))
{
    dsConfig.ReadXml(strFileName);
}


這寫法很不幸的,在使用 windows 排程時會發生找不到 xml 檔的問題。

於是我改用完整路徑的方法來改善。


首先,透過 GetExecutingAssembly().Location 取得執行檔的完整檔名路徑
System.Reflection.Assembly.GetExecutingAssembly().Location


接著只取執行檔的完整路徑(不含檔名)
Path.GetDirectoryName(FileName)

所以修改後的程式就變成:
DataSet dsConfig=new DataSet();
//取得執行路徑
string strExecPath = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
//取得 .xml 設定檔完整路徑,windows 排程需使用完整路徑設定
string strFullPath=string.Format("{0}\\{1}",strExecPath,setupFile);


if(System.IO.File.Exists(strFullPath))
{
  dsConfig.ReadXml(strFullPath);
}


原來,將程式改寫為 windows 排程,還需要考慮是否使用「完整路徑」的問題啊!

參考:Windows server 2008 排程無法執行

1 則留言: