|
本サイトは移転しました。旧アドレスからのリダイレクトは2025年03月31日(月)まで有効です。
|
🛈 | ✖ |
Code::Blocksの[Tool]メニューおよび[Tools+]メニューによる外部ツール起動時挙動をソースコードから解析する。
外部ツールはToolsManager::OnToolClick(sdk\toolsmanager.cpp:372)を介しToolsManager::Execute(sdk\toolsmanager.cpp:81)が起動する。
外部ツールはwxWidgetsライブラリのwxExecute関数で子プロセスとして起動する。
commandは外部ツールを起動するコマンド文字列(コマンド名とコマンド実引数)、flagsは起動オプションフラグ、callbackはwxProcessインスタンスポインタで外部ツール終了時処理と標準入出力リダイレクトを担当する。callbackがNULLあるいはリダイレクトしない場合は外部ツールは表示で起動し、リダイレクトする場合は非表示で起動する。標準入出力を持たないデスクトップアプリケーションを外部ツールとしてもこれに従う。この動作はフラグにwxEXEC_SHOW_CONSOLE(=wxEXEC_NOHIDE)またはwxEXEC_HIDE_CONSOLEを加えることでオーバーライトできる。
ToolsManager::OnToolClickは最初にPipedProcessインスタンスポインタであるメンバ変数m_pProcessを検査し、これがNULLでない場合はメッセージループにアタッチされた外部ツールが起動済みとして新たな外部ツールを起動せずリターンする。NULLの場合は起動オプションを示す列挙値の定める実引数でwxExecute関数をコールして外部ツールを起動する。
オプション | 列挙値 | command | flags | callback |
---|---|---|---|---|
Launch tool in a new console window and wait for a keypress when done | LAUNCH_NEW_CONSOLE_WINDOW | cb_console_runner.exe cmd params | wxEXEC_ASYNC | PipedProcess(pipe=false) |
Launch tool hidden with standard output redirect | LAUNCH_HIDDEN | cmd params | wxEXEC_ASYNC | PipedProcess(pipe=true) |
Launch tool visible (without output redirection) | LAUNCH_VISIBLE | cmd params | wxEXEC_ASYNC|wxEXEC_NOHIDE | PipedProcess(pipe=false) |
Launch tool visible detached (without output redirection) | LAUNCH_VISIBLE_DETACHED | cmd params | wxEXEC_ASYNC|wxEXEC_NOHIDE | NULL |
commandにおいてcmdは外部ツールのコマンド名、paramsはコマンド実引数とする。cb_console_runner.exe(tools\ConsoleRunner\main.cpp)はCode::Blocksに付属するコンソールアプリケーションで、実引数として与えられる外部ツール起動文字列を子プロセスとして起動し終了後にキー入力待ち一時停止する。メッセージループに外部ツールをアタッチする場合、wxProcessクラスを継承するPipedProcessクラス(include\pipedprocess.h:18)の新たなインタンスを構築し、m_pProcessにそのポインタを代入してwxExecute仮引数のcallbackへ渡す。外部ツールが終了するとPipedProcess::OnTerminate(sdk\pipedprocess.cpp:208)が終了イベントを送出し、ハンドラToolsManager::OnToolTerminated(sdk\toolsmanager.cpp:379)がm_pProcessにNULLを代入する(処理イベントはEVT_END_PROCESSではなくカスタムなのでインスタンスは自己解体する)。PipedProcessコンストラクタの仮引数pipeにtrueを与えると、wxProcess::Redirectをコールして標準入出力リダイレクトを可能とする。従ってLAUNCH_HIDDENのみリダイレクトしデフォルトで外部ツールは非表示起動となり、その他はデフォルトで表示起動なのでwxEXEC_NOHIDEは冗長である。
これで以下の全ての動作が説明できる。出力先がコマンドプロンプトの場合は新たに表示するコマンドプロンプトへ出力する。
オプション | アプリケーション | 出力先 | 表示 | メッセージループ | ツール終了時 |
---|---|---|---|---|---|
Launch tool in a new console window and wait for a keypress when done | コンソール | コマンドプロンプト | - | アタッチ | 一時停止 |
デスクトップ | コマンドプロンプト | メインウィンドウ | |||
Launch tool hidden with standard output redirect | コンソール | [Logs & others|Code::Blocks] | - | アタッチ | 終了 |
デスクトップ | - | 非表示 | |||
Launch tool visible (without output redirection) | コンソール | コマンドプロンプト | - | アタッチ | 終了 |
デスクトップ | - | メインウィンドウ | |||
Launch tool visible detached (without output redirection) | コンソール | コマンドプロンプト | - | デタッチ | 終了 |
デスクトップ | - | メインウィンドウ |
[Logs & others|Code::Blocks]ウィンドウへの出力について説明を追加する。
PipedProcessクラスはアイドルイベントハンドラPipedProcess::OnIdle(sdk\pipedprocess.cpp:229)からPipedProcess::HasInput(sdk\pipedprocess.cpp:173)をコールする(ソースコード上は定期タイマーハンドラ利用の痕跡も認められるが実行化されていない)。
wxProcess::IsInputAvailableあるいはwxProcess::IsErrorAvailableで出力有無を確認し、必要ならcbEVT_PIPEDPROCESS_STDOUTあるいはcbEVT_PIPEDPROCESS_STDERRを送出する。このイベントはToolsManager::OnToolStdOutput(sdk\toolsmanager.cpp:392)あるいはToolsManager::OnToolErrOutput(sdk\toolsmanager.cpp:397)が捉えログウィンドウ([Logs & others|Code::Blocks]ウィンドウ)へ出力される。
外部ツールはToolsPlus::OnRunTarget(plugins\contrib\ToolsPlus\ToolsPlus.cpp:260)が起動する。
起動オプションで分岐フラグが設定され処理が選択される。windowed分岐以外では適切な実引数をcommandへ与えwxExecute関数をコールして外部ツールを起動する。windowed分岐では[Tool Output]ウィンドウ管理クラスShellManagerのインスタンスポインタであるメンバ変数m_shellmgrを用いてShellManager::LaunchProcess(contrib\ToolsPlus\ShellCtrlBase.cpp:136)をコールする。
processcmdは外部ツールを起動するコマンド文字列である。typeの実引数"Piped Process Control"によりShellCtrlBase抽象クラスを継承するPipedProcessCtrlインスタンスを作成しポインタをshellに保持する。shellメンバ関数PipedProcessCtrl::LaunchProcess(plugins\contrib\ToolsPlus\PipedProcessCtrl.cpp:92)をprocesscmdを実引数としてコールする。最後にshellをShellManagerクラスの管理するノートブックコントロール(m_nbメンバ変数)へ[Tool Output]ウィンドウとして挿入する。
wxProcessインスタンスを作成しwxProcess::Redirectをコールして入出力リダイレクトを可能とする。processcmdとwxProcessインスタンスポインタm_procを実引数としてwxExecute関数をコールして外部ツールを起動する。
以上から各起動オプションがwxExecute関数へ渡す値をまとめる。
オプション | 分岐フラグ | command | flags | callback |
---|---|---|---|---|
Tools Output Window | windowed | cmd prams | wxEXEC_ASYNC | wxProcess |
Code::Blocks Console | console | cb_console_runner.exe cmd params | wxEXEC_ASYNC | NULL |
Standard Shell | 無し | cmd params | wxEXEC_ASYNC | NULL |
windowed分岐のみ標準入出力がリダイレクトされ外部ツールは非表示起動する。出力先がコマンドプロンプトの場合は新たに表示するコマンドプロンプトへ出力する。
オプション | アプリケーション | 出力先 | 表示 | メッセージループ | ツール終了時 |
---|---|---|---|---|---|
Tools Output Window | コンソール | [Tool Output] | - | デタッチ | 終了 |
デスクトップ | - | 非表示 | |||
Code::Blocks Console | コンソール | コマンドプロンプト | - | デタッチ | 一時停止 |
デスクトップ | コマンドプロンプト | メインウィンドウ | |||
Standard Shell | コンソール | コマンドプロンプト | - | デタッチ | 終了 |
デスクトップ | - | メインウィンドウ |
[Tool Output]ウィンドウへの出力について説明を追加し、特にその出力がASCII文字だけを正しく表示する理由を明らかにする。
ShellManagerクラスインスタンスは定期的なタイマーイベントハンドラShellManager::OnPollandSyncOutput(contrib\ToolsPlus\ShellCtrlBase.cpp:232)でノートブックコントロール(m_nb)の全てのShellCtrlBase抽象クラスの継承インスタンスを走査し出力を更新する。
外部ツールの出力先として追加されたPipedProcessCtrlインスタンス(すなわち[Tool Output]ウィンドウ)はPipedProcessCtrl::SyncOutput(plugins\contrib\ToolsPlus\PipedProcessCtrl.cpp:152)で出力を更新する。
標準出力はm_textctrlメンバ変数に格納されたコントロールへ出力される。m_textctrlはPipedTextCtrlクラスインスタンスポインタであり、PipedTextCtrlはScintillaエディタコンポーネントをラップするwxScintillaクラス(wxScintillaはwxStyledTextCtrlの実装クラスでもある)を継承するのでユニコード文字列を表示できる。問題は出力を受け取ったバッファbuf0からコントロールへ出力するwxString型文字列m_latestへの変換にwxString::FromAsciiを用いていることで、これにより正しく表示できる文字がASCII文字に限定されてしまう。