DOS コマンド実行用コンポーネントです。DOS コマンドをバックグラウンドで実行しながら、コマンドが標準出力に出力した文字列を利用することができます。何らかの処理を行う DOS コマンドがすでにあり、その標準出力をウィンドウに表示したい、などというときに使います。
このコンポーネントにはイベントが 7 つあります。
DOS コマンドが標準出力あるいは標準エラー出力デバイスに 1 文字出力するたびに呼ばれます。イベントハンドラのプロトタイプは
void __fastcall TForm1::DosCommand1OutputChar( TObject* Sender, char Ch );
のような感じになります。
DOS コマンドが標準出力あるいは標準エラー出力デバイスに文字列を一行出力するたびに呼ばれます。イベントハンドラのプロトタイプは
void __fastcall TForm1::DosCommand1OutputLine( TObject* Sender, const AnsiString& Str );
のような感じになります。
DOS コマンドが標準出力デバイスに 1 文字出力するたびに呼ばれます。イベントハンドラのプロトタイプは
void __fastcall TForm1::DosCommand1StdOutChar( TObject* Sender, char Ch );
のような感じになります。
DOS コマンドが標準出力デバイスに文字列を一行出力するたびに呼ばれます。イベントハンドラのプロトタイプは
void __fastcall TForm1::DosCommand1StdOutLine( TObject* Sender, const AnsiString& Str );
のような感じになります。
DOS コマンドが標準エラー出力デバイスに 1 文字出力するたびに呼ばれます。イベントハンドラのプロトタイプは
void __fastcall TForm1::DosCommand1StdErrChar( TObject* Sender, char Ch );
のような感じになります。
DOS コマンドが標準エラー出力デバイスに文字列を一行出力するたびに呼ばれます。イベントハンドラのプロトタイプは
void __fastcall TForm1::DosCommand1StdErrLine( TObject* Sender, const AnsiString& Str );
のような感じになります。
DOS コマンドの実行が終わると呼ばれます。イベントハンドラのプロトタイプは
void __fastcall TForm1::DosCommand1Terminate( TObject* Sender );
のような感じになります。
このコンポーネントにはプロパティが三つあります。
DOS コマンドが実行中のときにはtrue, そうでないときにはfalseを返すプロパティです。読み出し専用プロパティです。
実行したコマンドの終了コードです。ただし、コマンド実行が終了していないと意味を持ちません。読み出し専用プロパティです。
実行する DOS コマンドプロセスのスレッドの実行プライオリティを指定します。
| dcpRealTime | プロセスには最も高いプライオリティが与えられます。このプロセスのスレッドは他の全てのプロセスのスレッドよりも先に実行されますので、あまり実行時間の短くないプロセスだとディスクキャッシュがフラッシュされなかったり、マウスが応答しなくなったりします ( Win32 SDK ヘルプより )。従って、このプライオリティはあまり指定しないほうがいいでしょう。 |
| cpHigh | プロセスにはリアルタイムタスクの次に高いプライオリティが与えられます。標準またはアイドルの優先順位のプロセスのスレッドよりも先に実行されます。このプライオリティをもつプロセスは利用可能な CPU サイクルをほとんどすべて使い果たしてしまいます。このため、 このプライオリティを利用するときは細心の注意が必要です ( Win32 SDK ヘルプより )。 |
| dcpNormal | プロセスには標準のプライオリティが与えられます。デフォルトはこのプライオリティです。 |
| dcpIdle | プロセスには最も低いプライオリティが与えられます。このプロセスのスレッドは、 システムがアイドル状態のときだけ実行され、 より高い優先順位クラスで実行されているほかのプロセスのスレッドよりも後に実行されます ( Win32 SDK ヘルプより )。 |
このコンポーネントにはTComponentから継承されたものの他にパブリックメンバ関数が三つあります。
command引数で与えられたコマンドをdir引数で与えられたディレクトリで実行します。コマンド実行後、すぐに戻ります。返値がtrueの場合は実行成功、falseの場合は実行失敗を表わします。このコンポーネントは一回に一つのコマンドしか実行できませんので、すでにコマンドが実行中の場合はfalseを返します。同時に二つ以上のコマンドを実行させたい場合にはその数だけTDosCommandコンポーネントのインスタンスが必要となります。
コマンドが終了するまで待ちます。
コマンドを強制終了させます。
PriorityプロパティのデフォルトはdcpNormalですが、この場合実行速度が非常に遅い場合があります。そのようなときにはPriorityにdcpHighを指定してください。ただし、あまりいい解決方法ではありません。遅くなる原因は、DOS コマンドからの標準出力をパイプ経由で読み込むスレッドの中で PeakNamedPipe API と GetExitCodeProcess API 呼び出しをループでまわしている部分であると思われるのですが、私にはこれ以外の方法はわかりませんでした。何かスマートな解決方法をご存知の方は教えてください。
このコンポーネントの配布・改変・利用は完全に自由です。連絡などは一切無用です。ただし、本コンポーネントの不具合による損害の責任は負いません。
このコンポーネントの作成にあたり、同志社大学工学部知識工学科の川崎高志さん、east_d さんにアドバイスをいただきました。また、C++Builder MLの皆様にも感謝いたします。
| 1998/ 2/ 1: | Inside Windows 1998 年 1 月号を参考にして作る。ReadFile API でパイプからの読み込みがブロッキングされてうまく動かなかった。 |
| 1998/ 2/ 1: | 川崎さんにアドバイスをもらい、PeekNamedPipe API を利用することによりとりあえず動くようになった。ただし、コマンドによっては実行速度が極端に遅い場合があった。 |
| 1998/ 2/ 2: |
TPipeReaderクラスをTDosCommandクラスの内部クラスにした。 コマンドの終了コードを得るためのプロパティ ( DWORD ExitCode ) を設けた。 コマンドが実行中かどうかを表わすプロパティ ( bool IsOnExecution ) を設けた。 コマンドの終了イベント ( OnTerminate ) を設けた。 |
| 1998/ 2/11: |
1 文字出力イベント ( OnOutputChar ) を設けた。それに伴い、1 行出力イベント名をOnOutput からOnOutputLineに変更し、かつ、どのTDosCommandインスタンスから生じたイベントなのかを識別するためにTObject* Senderをパラメータリストに加えた。 実行 DOS コマンドのプライオリティを設定できるようにした。PriorityにdcpHighを設定することにより、実行速度が極端に遅いということが避けられるようになった。 サンプルアプリケーションの動作を少し変更した。 |
| 1998/ 3/23: |
WaitForTermination()関数を WaitForSingleObject() API を使用するように変更した。 |
| 1998/ 4/11: |
BCB 1 と BCB 3 の両方に対応するようにソースを変更した。 |
| 1999/ 4/17: |
CreateProcessAPI の "Creation Flag" にDETACHED_PROCESSフラグに加えてCREATE_NO_WINDOWフラグを指定した。これにより、MAKE のように子プロセスを立ち上げるコマンドでも DOS 窓が開かないようになった。 パブリックメンバ関数の Execute に実行時のディレクトリを指定できるようにした。デフォルト引数として "" が与えてある。 あとは細かい修正。 |
| 1999/ 4/19: | パブリックメンバ関数Executeのdir ( 実行時のディレクトリ ) 引数を指定しなかった場合、実行できなくなっていたのを直した。 |
| 1999/ 9/ 1: |
east_d さんの指摘を受けて、パイプからの文字読み込みの部分を変更。 パイプのバッファチェックのループ内にSleep( 1 )を入れた。 パイプのバッファサイズを 256 にした(あまり関係ないかも)。 サンプルプログラムを BCB 4 用に変更。 そのほか細かい修正。 |
| 1999/ 9/21: |
標準出力と標準エラー出力のイベントハンドラを分離した。ただし、以前のバージョンとの互換性を取るため、OnOutputChar, OnOutputLineイベントは標準出力および標準エラー出力に出力された文字を渡すイベントとしてそのまま残した。 パイプからの読み込み部分を変更。パイプのバッファサイズ分だけバッファを用意し、PeekNamedPipe API でパイプ上にある文字分だけReadFile API で一気に読むようにした。ただ、以前こうやったときには確か文字出力の最後の部分が欠けて受け取れなかったような気が…。Windows 98 になって OK になったのかもしれない。 |
ご意見、ご希望、ご感想、バグレポート等がございましたら、
までお願いします。
Borland C++ Builder 用 DOS コマンド実行コンポーネントTDosCmd.zipをダウンロードするには、ここを押してください。