這一周嘗試著用C#寫了兩個背景程式,主程式用CreateProcess()傳遞命令列參數並建立進程。在實現的過程中,碰到了一個問題,命令列參數中如果帶有空格該如何處理。一直認為,命令列中的空格用作參數的分隔字元。如果參數內部有空格,該怎麼辦呢?譬如命令列的參數為“祝福 張學友 \Program Files\1 2 3.lrc”。
剛開始寫背景程式時,沒考慮到這個問題。後來ZWF在使用時問起,才注意到。經過商量,決定自己定義一個命令列格式,用|作為分隔字元。將“祝福 張學友 \Program Files\1 2 3.lrc”改為“祝福|張學友|\Program Files\1 2 3.lrc”。在背景程式中,首先將所有的參數合并,然後再通過分隔字元|解析各個欄位,代碼如下:
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
String temp = "";
string song, singer, path;
int head, tail;
// 合并命令列參數
for (int i = 0; i < args.Length; i++)
{
MessageBox.Show(args[i]);
temp += args[i];
temp += " ";
}
MessageBox.Show(temp);
try
{
// 解析合并後的命令列
head = temp.IndexOf('|', 0);
song = temp.Substring(0, head);
MessageBox.Show(song);
head += 1;
tail = temp.IndexOf('|', head);
singer = temp.Substring(head, tail - head);
MessageBox.Show(singer);
path = temp.Substring(tail + 1);
MessageBox.Show(path);
}
catch{}
}
}
}
主程式是用C++寫的,代碼如下:
int _tmain(int argc, _TCHAR* argv[])
{
TCHAR szCMD[MAX_PATH];
PROCESS_INFORMATION pi;
STARTUPINFO sii;
memset(&sii, 0, sizeof(sii));
sii.cb = sizeof(sii);
sii.wShowWindow = SW_SHOW;
sii.dwFlags = STARTF_USESHOWWINDOW;
// 自訂格式的命令列參數
wcscpy(szCMD, L" 祝福|張學友|\\Program Files\\1 2 3.lrc");
// 使用系統支援的命令列參數
//wcscpy(szCMD,L" 祝福 張學友 \"\\Program Files\\1 2 3.lrc\"");
CreateProcess(_T(".\\ConsoleApplication1.exe"), szCMD,
NULL, NULL, 0, 0, NULL, NULL, &sii, &pi);
return 0;
}
注意,wcscpy(szCMD, L" 祝福|張學友|\\Program Files\\1 2 3.lrc");中祝福前必須留一個空格,否則會導致背景程式接收的命令列不完整。關於這一點,請參考《C++和C#程式之間命令列參數傳遞和接收》,博主整理的非常細緻。MSDN中有關C#命令列參數的說明,Main() 和命令列參數(C# 編程指南),其中提到了“與 C 和 C++ 不同,C#程式的名稱不會被當作第一個命令列參數”。
雖然通過自訂命令列的方式,解決了命令列參數本身帶有空格的問題,但總感覺有點怪。這是參數不多,如果參數多了怎麼辦?按理來說,命令列參數的解析規則不能這麼簡單。在MSDN中查了一下,有其具體的解析規則Parsing C Command-Line Arguments。其中第一個樣本就是解決命令列參數中帶有空格的問題,只要將該參數放在一對雙引號內就可以了。所以,將“祝福 張學友 \Program Files\1 2 3.lrc”改成“ 祝福 張學友 \"\Program Files\1 2 3.lrc\"”即可。通過實驗證明,這種方法可行,且簡單方便。