有時我們的程式需要啟動其它程式,可能是為了利用它已有的功能,也可能是為了達到某種需要。那麼怎樣來啟動我們需要的程式呢?
我暫時知道有4種方法:
1、調用API: int system( const char *command );
你可以傳入一命令,啟動某個程式。如"ping www.vczx.com", "YourExe"等等
不過這裡有幾點要值得注意:
(1)、他不會立即返回,直到你啟動的程式執行完成。
(2)、如果你啟動是windows程式,它仍然會啟動一個控制台,這就給人感覺太差勁了,但如果本身是控制台的,而且又需要等待它的完成,那這將是比較好的選擇。
(3)、它的傳回值代表是否執行成功以及程式的退出碼。
2、調用API:
UINT WinExec(
LPCSTR lpCmdLine, // command line
UINT uCmdShow // window style
);
這個API與API:system同樣的簡單,都是使用命令列型式。
不過它與API:system相比,有幾個優點:
(1)、它將啟動了一個新進程,並且立即返回,因此你的程式無需等待。
(2)、它多了一個參數:uCmdShow,通過它你可以一定程度上控制項表單的顯示,比如讓它後台運行而不顯示出來。
(3)、它無論啟動控制台程式還是windows程式都只做你想要做的事,不會有上面啟動windows程式時先啟動控制台視窗的動作。
它的不足之處:
(1)、它完全與本進程脫離,無法做些必要的控制
(2)、無法得知啟動的程式是否退出。
(3)、得不到啟動的程式的退出碼。
等等
3、調用:
HINSTANCE ShellExecute(
HWND hwnd,
LPCTSTR lpVerb,
LPCTSTR lpFile,
LPCTSTR lpParameters,
LPCTSTR lpDirectory,
INT nShowCmd
);
它也有WinExec同樣的缺點。
它雖然傳回一個HINSTANCE,但他並不是真正的控制代碼,我們僅能拿它來做一些錯誤值檢查。
但它的功能比前兩者更強大,它執行系統的Shell命令。
1、2中如果傳入“XX.txt”,它們將不能成功執行,ShellExecute卻能很好地執行,它將啟動一個預設的文文書處理程式來開啟它。
1、2中如果傳入“www.vczx.com”,將不能成功執行,而ShellExecute卻能很好地執行,它將啟動一個預設瀏覽器來開啟這個網站。
參數講解:
參數1 hwnd:一表單控制代碼,將作為啟動的程式的父表單。
參數2 lpVerb:你想執行的操作(edit 、explore、find、open、print、properties),你也可以傳入NULL值,它將執行預設操作(win2000以前與以後處理略有差別,請見MSDN)。
參數3 lpFile:一檔案名稱或操作的對象。
參數4 lpParameters:如果lpFile是一可執行檔,這個將作為它的參數。它的格式由執行的操作決定。而且當lpFile為一document檔案時,此參數需為NULL。
參數5 lpDirectory:指定它的工作目錄。
參數6 nShowCmd:表單顯示的控制。
以下是幾個例子:
//啟動一個Dos命令, 啟動windows程式相同
::ShellExecute(this->GetSafeHwnd(), NULL, "ping", "www.vczx.com", NULL, SW_SHOWNORMAL);
//開啟一個檔案
::ShellExecute(this->GetSafeHwnd(), "open", "ReadMe.txt", NULL, NULL, SW_SHOWNORMAL);
//上面的動詞可傳可不傳,但如果"ReadMe.txt"為"ReadMe.bat"那就得指定,否則將會當命令執行,而不是開啟它。
//可開啟目錄
::ShellExecute(this->GetSafeHwnd(), "open", "c:", NULL, NULL, SW_SHOWNORMAL);
//可開啟網頁
::ShellExecute(this->GetSafeHwnd(), "open", "www.vczx.com", NULL, NULL, SW_SHOWNORMAL);
//瀏覽一個目錄
ShellExecute(handle, "explore", "c:"NULL, NULL, SW_SHOWNORMAL);
//查看一個檔案或目錄的屬性
//使用ShellExecuteEx,實現請見所附源碼對應部分
如果沒有特殊的控制要求,它己能為我們做很了,但當我們一定要能控制項這個啟動的進程時,那我們就得使用第4點了。
4:調用API:
BOOL CreateProcess(
LPCTSTR lpApplicationName, // name of executable module
LPTSTR lpCommandLine, // command line string
LPSECURITY_ATTRIBUTES lpProcessAttributes, // SD
LPSECURITY_ATTRIBUTES lpThreadAttributes, // SD
BOOL bInheritHandles, // handle inheritance option
DWORD dwCreationFlags, // creation flags
LPVOID lpEnvironment, // new environment block
LPCTSTR lpCurrentDirectory, // current directory name
LPSTARTUPINFO lpStartupInfo, // startup information
LPPROCESS_INFORMATION lpProcessInformation // process information
);
往往看到這個函數就讓人生畏,它參數多,而且參數類型也如此莫生。是的,正是因為如此它才功能強大!
但不要怕,作為一般使用,非常簡單!下面便是一個簡單的例子(啟動記事本):
STARTUPINFO StartInfo;
PROCESS_INFORMATION pinfo;
//對程式的啟動資訊不作任何設定,全部清0
memset(&StartInfo,0,sizeof(STARTUPINFO));
StartInfo.cb = sizeof(STARTUPINFO);//設定結構的大小
BOOL ret=CreateProcess(
NULL, //啟動程式路徑名
"notepad.exe", //參數(當exeName為NULL時,可將命令放入參數前)
NULL, //使用預設進程安全屬性
NULL, //使用預設安全執行緒屬性
FALSE, //控制代碼不繼承
NORMAL_PRIORITY_CLASS, //使用正常優先順序
NULL, //使用父進程的環境變數
NULL, //指定工作目錄
&StartInfo, //子進程主視窗如何顯示
&pinfo); //用於存放新進程的返回資訊
這樣在建立成功這後我們就可以從pinfo中找到它的:進程控制代碼,線程控制代碼,進程ID,線程ID
在附件源碼中示範了進程式的啟動,停止。(實際上我們可以通過很多方式如記憶體共用、父進程表單句體傳入仍後從訊息中獲得子進程表單控制代碼等,來實現更多的控制。)
想很好地掌握CreateProcess,可參見人民郵電出版社出版的<< Windows系統編程 >>,它的“進程”部份作了很詳盡的說明。