# 20.7 調用別的應用程序
有時候你需要從你的應用程序中啟動別的應用程序,可能是一個瀏覽器或者是你自己寫的另外一個程序.wxExecute函數是一個功能很強大的函數,它的功能包括: 帶參數或者不帶參數調用別的程序,同步或者異步執行程序,搜集別的程序的輸出,以及重定向別的程序的輸入和輸出以便實現和當前程序的交互.
啟動一個應用程序
下面是wxExecute函數的一個簡單的例子:
```
// 異步執行程序(默認行為),函數將會立即返回.
wxExecute(wxT("c:\\windows\\notepad.exe"));
// 同步執行程序,函數在Notepad程序退出以后才會返回.
wxExecute(wxT("c:\\windows\\notepad.exe c:\\temp\\temp.txt"),
wxEXEC_SYNC);
```
注意一般來說你可以將參數和可執行文件用引號括起來,這在路徑中包含空格的時候是很有用的.
打開文檔
如果你啟動一個外部程序的目的是打開一個文檔,在Windows或者Linux平臺上,你可以使用wxMimeTypesManager 類.你可以使用它來獲得打開某種類型的文檔所需要執行的程序的路徑,然后使用它來構造wxExecute函數的參數,比如,如果你想打開一個HTML文件,你可以使用下面的方法:
```
wxString url = wxT("c:\\home\\index.html");
bool ok = false;
wxFileType *ft = wxTheMimeTypesManager->
GetFileTypeFromExtension(wxT("html"));
if ( ft )
{
wxString cmd;
ok = ft->GetOpenCommand(&cmd,
wxFileType::MessageParameters(url, wxEmptyString));
delete ft;
if (ok)
{
ok = (wxExecute(cmd, wxEXEC_ASYNC) != 0);
}
}
```
不幸的是,這種方法不適用于Mac OSX平臺,因為Mac OSX平臺使用完全不同的文檔打開機制.對于任何別的文件類型,最好使用系統提供的Finder程序來打開,而對于HTML文件,你可以直接使用系統函數 ICLaunchURL.wxExecute有時候并不是最好的選擇,在windows平臺上,如果要打開HTML文件,你可以直接使用 ShellExecute函數會更有效率.即使在Unix平臺上,你可能也要作好指定的程序不存在的準備,如果它確實不存在,你可以考慮使用別的程序比如 htmlview.
為了避免上述的這些問題,我們在隨書光盤的examples/chap20/launch目錄中,實現了一些函數,比如: wxLaunchFile,wxViewHTMLFile,wxViewPDFFile,wxPlaySoundFile,它們的功能一目了然,并且它們可以同時支持Windows,Linux和Mac OsX平臺.
wxLaunchFile是一個普通意義上的文本打開函數.參數包括一個文檔文件名或者一個可執行文件名附帶可選的參數,以及一個可選的錯誤消息字符串,這個字符串在執行失敗的時候顯示給用戶.如果當前正在打開的文檔是HTML類型的文檔,wxLaunchFile函數將調用 wxViewHTMLFile函數.在Mac OsX平臺上,這個函數將使用Finder打開文檔,而在別的平臺上則使用wxMimeTypesManager.注意在Mac OSX平臺上,有時候文檔會在非活動的窗口上打開,這時候你可以通過osascript這個命令行工具來將它提到前臺,如下所示(比如):
```
wxExecute(wxT("osascript -e \"tell application \\\"AcmeApp\\\"\" -e
\"activate\" -e \"end tell\""));
```
在Linux平臺上, wxViewHTMLFile, wxViewPDFFile和wxPlaySoundFile都包含fallbacks機制以便在相應的可執行文件不存在的時候使用.你可以按照自己的需要調整相應的fallbacks設置. wxPlaySoundFile是用來使用外部程序播放那些大型的聲音文件的,如果只是播放一個很小的聲音文件,你可以直接使用wxSound.
重定向進程的輸入和輸出
有時候,你希望捕獲另外一個進程的輸入和輸出,以便你或者你的用戶可以控制那個進程.比起重頭寫實現某個功能的代碼來說,這樣作顯然可以給你減少不少的工作量.而wxExecute可以幫助實現捕獲和控制那些控制臺程序的輸入和輸出.
要實現這個功能,你需要在調用wxExecute函數的時候傳遞一個wxProcess的實例,這個實例的OnTerminate函數將在進程結束的時候被調用,這個實例可以用來捕獲進程的輸出或者控制進程的輸入.
在wxWidgets自帶的samples/exec目錄中,你可以找到各種各樣使用wxExecute的例子,我們也提供了另外一個例子,它將GDB集成進自己的程序中去,你可以參考examples/chap20/pipedprocess中的代碼.我們沒有提供用于工具條的那些小圖片以及整個可編譯的代碼,如果提供了這些,它將可以支持包括windows,linux和Mac OSX在內的各種平臺,只要那些平臺上安裝了GDB.
debugger.h和debugger.cpp文件實現了一個管道化的進程和一個窗口,這個窗口包含一個工具條和一個文本框,用來顯示GDB的輸出和從用戶那里獲取輸入并且把它發送給GDB.
textctrlex.h和textctrlex.cpp則實現了一個派生自wxStyledTextCtrl的控件,包括一些和wxTextCtrl兼容的函數和標準事件處理函數比如復制,剪切,粘貼,重做和撤消等.
processapp.h和processapp.cpp實現了一個應用程序類,這個類可以在空閑的時候處理來自多個進程的輸入.
GDB是通過下面的語句啟動的:
```
DebuggerProcess *process = new DebuggerProcess (this);
m_pid = wxExecute(cmd, wxEXEC_ASYNC, process);
```
可以使用下面的代碼殺死這個進程:
```
wxKill(m_pid, wxSIGKILL, NULL, wxKILL_CHILDREN);
```
要給調試器發送一個命令,將會設置一個內部的變量以便通知應用程序在空閑的時候處理這個輸入.
```
// 給調試器發送一個命令
bool DebuggerWindow::SendDebugCommand(const wxString& cmd,
bool needEcho)
{
if (m_process && m_process->GetOutputStream())
{
wxString c = cmd;
c += wxT("\n");
if (needEcho)
AddLine(cmd);
// 這個函數只是簡單的對m_input變量賦值
// OnIdle函數中的HasInput函數將檢查這個變量.
m_process->SendInput(c);
return true;
}
return false;
}
```
HasInput函數被應用程序在其空閑時間周期性的調用,它的責任是發送用戶輸入的命令到進程并且從進程讀取來自標準輸出和標準錯誤的輸出:
```
bool DebuggerProcess::HasInput()
{
bool hasInput = false;
static wxChar buffer[4096];
if ( !m_input.IsEmpty() )
{
wxTextOutputStream os(*GetOutputStream());
os.WriteString(m_input);
m_input.Empty();
hasInput = true;
}
if ( IsErrorAvailable() )
{
buffer[GetErrorStream()->Read(buffer, WXSIZEOF(buffer) -
1).LastRead()] = _T('\0');
wxString msg(buffer);
m_debugWindow->ReadDebuggerOutput(msg, true);
hasInput = true;
}
if ( IsInputAvailable() )
{
buffer[GetInputStream()->Read(buffer, WXSIZEOF(buffer) -
1).LastRead()] = _T('\0');
wxString msg(buffer);
m_debugWindow->ReadDebuggerOutput(buffer, false);
hasInput = true;
}
return hasInput;
}
```
注意上面這個例子和wxWidgets自帶的exec例子的一個關鍵的不同在于,exec例子每次從進程讀取一行,如果進程的輸出沒有帶換行符,將導致應用程序被阻塞.而在我們的例子中,使用了一個緩沖區來保存盡可能多的輸入,這是一種更安全的作法.
ProcessApp類可以直接被用作你的應用程序的基類,或者你可以拷貝它的成員函數到你的應用程序類中去.它維護了一個進程列表,進程可以通過RegisterProcess和UnregisterProcess函數登記和注銷, 進程輸入和輸出的處理在系統空閑時間完成.如下所示:
```
// 任何緩存的輸入都在系統空閑時處理
bool ProcessApp::HandleProcessInput()
{
if (!HasProcesses())
return false;
bool hasInput = false;
wxNode* node = m_processes.GetFirst();
while (node)
{
PipedProcess* process = wxDynamicCast(node->GetData(), PipedProcess);
if (process && process->HasInput())
hasInput = true;
node = node->GetNext();
}
return hasInput;
}
void ProcessApp::OnIdle(wxIdleEvent& event)
{
if (HandleProcessInput())
event.RequestMore();
event.Skip();
}
```
- 第一章 介紹
- 1.1 為什么要使用wxWidgets?
- 1.2 wxWidgets的歷史
- 1.3 wxWidgets社區
- 1.4 wxWidgets和面向對象編程
- 1.5 wxWidgets的體系結構
- 1.6 許可協議
- 第一章小結
- 第二章 開始使用
- 2.1 一個小例子
- 2.2 應用程序類
- 2.3 Frame窗口類
- 2.4 事件處理函數
- 2.5 Frame窗口的構造函數
- 2.6 完整的例子
- 2.7 wxWidgets程序一般執行過程
- 2.8 編譯和運行程序
- 第二章小結
- 第三章 事件處理
- 3.1 事件驅動編程
- 3.2 事件表和事件處理過程
- 3.3 過濾某個事件
- 3.4 掛載事件表
- 3.5 動態事件處理方法
- 3.6 窗口標識符
- 3.7 自定義事件
- 第三章小結
- 第四章 窗口的基礎知識
- 4.1 窗口解析
- 4.2 窗口類概覽
- 4.3 基礎窗口類
- 4.4 頂層窗口
- 4.5 容器窗口
- 4.6 非靜態控件
- 4.7 靜態控件
- 4.8 菜單
- 4.9 控制條
- 第四章小結
- 第五章繪畫和打印
- 5.1 理解設備上下文
- 5.2 繪畫工具
- 5.3 設備上下文中的繪畫函數
- 5.4 使用打印框架
- 5.5 使用wxGLCanvas繪制三維圖形
- 第五章小節
- 第六章處理用戶輸入
- 6.1 鼠標輸入
- 6.2 處理鍵盤事件
- 6.3 處理游戲手柄事件
- 第六章小結
- 第七章使用布局控件進行窗口布局
- 7.1 窗口布局基礎
- 7.2 窗口布局控件
- 7.3 使用布局控件進行編程
- 7.4 更多關于布局的話題
- 第七章小結
- 第八章使用標準對話框
- 8.1信息對話框
- 8.2 文件和目錄對話框
- 8.3 選擇和選項對話框
- 8.4 輸入對話框
- 8.5 打印對話框
- 第八章小結
- 第九章創建定制的對話框
- 9.1 創建定制對話框的步驟
- 9.2 一個例子:PersonalRecordDialog
- 9.3 在小型設備上調整你的對話框
- 9.4 一些更深入的話題
- 9.5 使用wxWidgets資源文件
- 第九章小結
- 第十章使用圖像編程
- 10.1 wxWidgets中圖片相關的類
- 10.2 使用wxBitmap編程
- 10.3 使用wxIcon編程
- 10.4 使用wxCursor編程
- 10.5 使用wxImage編程
- 10.6 圖片列表和圖標集
- 10.7 自定義wxWidgets提供的小圖片
- 第十章小結
- 第十一章剪貼板和拖放操作
- 11.1 數據對象
- 11.2 使用剪貼板
- 11.3 實現拖放操作
- 第十一章小結
- 第十二章高級窗口控件
- 12.1 wxTreeCtrl
- 12.2 wxListCtrl
- 12.3 wxWizard
- 12.4 wxHtmlWindow
- 12.5 wxGrid
- 12.6 wxTaskBarIcon
- 12.7 編寫自定義的控件
- 第十二章小結
- 第十三章數據結構類
- 13.1 為什么沒有使用STL?
- 13.2 字符串類型
- 13.3 wxArray
- 13.4 wxList和wxNode
- 13.5 wxHashMap
- 13.6 存儲和使用日期和時間
- 13.7 其它常用的數據類型
- 第十三章小結
- 第十四章文件和流操作
- 14.1 文件類和函數
- 14.2 流操作相關類
- 第十四章小結
- 第十五章內存管理,調試和錯誤處理
- 15.1 內存管理基礎
- 15.2 檢測內存泄漏和其它錯誤
- 15.3 構建自防御的程序
- 15.4 錯誤報告
- 15.5 提供運行期類型信息
- 15.6 使用wxModule
- 15.7 加載動態鏈接庫
- 15.8 異常處理
- 15.9 調試提示
- 第十五章小結
- 第十六章編寫國際化程序
- 16.1 國際化介紹
- 16.2 從翻譯說起
- 16.3 字符編碼和Unicode
- 16.4 數字和日期
- 16.5 其它媒介
- 16.6 一個小例子
- 第十六章小結
- 第十七章編寫多線程程序
- 17.1 什么時候使用多線程,什么時候不要使用
- 17.2 使用wxThread
- 17.3 用于線程同步的對象
- 17.4 多線程的替代方案
- 第十七章小結
- 第十八章使用wxSocket編程
- 18.1 Socket類和功能概覽
- 18.2 Socket及其基本處理介紹
- 18.3 Socket標記
- 18.4 使用Socket流
- 18.5 替代wxSocket
- 第十八章小結
- 第十九章使用文檔/視圖框架
- 19.1 文檔/視圖基礎
- 19.2 文檔/視圖框架的其它能力
- 19.3 實現Undo/Redo的策略
- 第十九章小結
- 第二十章完善你的應用程序
- 20.1 單個實例和多個實例
- 20.2 更改事件處理機制
- 20.3 降低閃爍
- 20.4 實現聯機幫助
- 20.5 解析命令行參數
- 20.6 存儲應用程序資源
- 20.7 調用別的應用程序
- 20.8 管理應用程序設置
- 20.9 應用程序安裝
- 20.10 遵循用戶界面設計規范
- 20.11 全書小結