ShellExecuteEx()関数について

解決


名古屋  2005-04-27 19:46:47  No: 57215

おせわになります。

VC++6.0から、以下のコードによりアプリケーションを起動しています。

    ShellExecuteEx(&test);  //起動
    WaitForSingleObject(test.hProcess,INFINITE);//終了待ち

上記のコードを起動すると、数分程度、処理がVC++側に戻ってこない
のですが、「中止ボタン」により途中で起動を中止させたいと思っています
が可能でしょうか?また可能である場合その方法を教えてください。

よろしくお願いします。


シャノン  2005-04-28 09:40:17  No: 57216

> WaitForSingleObject(test.hProcess,INFINITE);//終了待ち

で待っている所為です。
アプリを起動するのを別のスレッドで行えば、可能だと思われます。


名古屋  2005-04-28 19:10:43  No: 57217

Resありがとうございます。

別スレッドで起動する方法を調べました。
AfxBeginThreadで実行すればよいことまでは
解かったのですが、中止の方法が解かりません。
ご教授していただけたらと思います。


シャノン  2005-04-29 07:52:06  No: 57218

対象アプリが起動してからの初期化処理などに時間がかかるのではなく、ShellExecuteEx での起動処理(ShellExecuteEx から戻ってくるまで)に時間がかかるのでしょうか。それも妙な話ですが。

対象のアプリが、その中断したい長い処理を行っている間、親(つまり ShellExecuteEx を実行する自プログラム)と、何らかの方法で通信することができるのであれば、キャンセルされたことを子(起動された側)に伝えることができるでしょう。
メッセージとか、パイプとか、イベントとか。

ShellExecuteEx から帰ってくるまでの時間が長く、その間、子に手をつけることができないのであれば、もうそれは諦めて放っておきましょう。
主スレッド側でキャンセルボタンが押されたことをどこかに記憶しておいて、サブスレッドの方で制御が戻ってきたときに、既にキャンセルボタンが押されていたら、子の起動はなかったものとして即終了してしまいましょう。


名古屋  2005-05-02 23:00:09  No: 57219

Resありがとうございます。

>対象アプリが起動してからの初期化処理などに時間がかかるのではなく、>ShellExecuteEx での起動処理(ShellExecuteEx から戻ってくるまで)に時間が>かかるのでしょうか。それも妙な話ですが。

ShellExecuteEx()で呼び出しているのは、計算処理を行う「exeファイル」
ですので、計算処理待ちの状態となります。

>対象のアプリが、その中断したい長い処理を行っている間、親(つまり >ShellExecuteEx を実行する自プログラム)と、何らかの方法で通信することがで>きるのであれば、キャンセルされたことを子(起動された側)に伝えることができ>るでしょう。
>メッセージとか、パイプとか、イベントとか。

子は「exeファイル」の形でしか存在せず、中身はブラックボックスであり、
起動するのみしかできないので、メッセージを渡すことはできない状況です。

>ShellExecuteEx から帰ってくるまでの時間が長く、その間、子に手をつけること>ができないのであれば、もうそれは諦めて放っておきましょう。
>主スレッド側でキャンセルボタンが押されたことをどこかに記憶しておいて、サブ>スレッドの方で制御が戻ってきたときに、既にキャンセルボタンが押されていた
>ら、子の起動はなかったものとして即終了してしまいましょう。

中断ボタンを押した後、即座に再度実行をした場合、
子スレッドが終了していないと問題が起きるような気がするのですがいかがでしょうか?
強制終了させる必要がやはりあるのでしょうか?

ご教授していただけたらと思います。


RAPT  2005-05-03 10:06:05  No: 57220

ShellExecute(), ShellExecuteEx() はWindowsの「関連づけ」で起動する
だけのもので、基本的に投げっぱなし、というイメージです。

プロセス管理をしたいのなら、CreateProcess()が便利だと思います。


シャノン  2005-05-04 01:46:56  No: 57221

> ShellExecute(), ShellExecuteEx() はWindowsの「関連づけ」で起動するだけのもので、基本的に投げっぱなし、というイメージです。
> プロセス管理をしたいのなら、CreateProcess()が便利だと思います。

どっちでも大して変らない気がする…。

> ShellExecuteEx()で呼び出しているのは、計算処理を行う「exeファイル」ですので、計算処理待ちの状態となります。

ShellExecuteEx は対象のアプリを起動したら即座に処理を返します。
対象のアプリが終了するまで待つようなことはしません。
それを踏まえると、「計算処理待ち」というのは「計算処理が始まるのを待っている状態」と解釈できますが、それでよろしいでしょうか?

> 中断ボタンを押した後、即座に再度実行をした場合、子スレッドが終了していないと問題が起きるような気がするのですがいかがでしょうか?
> 強制終了させる必要がやはりあるのでしょうか?

強制終了させる方法はありますが、望ましいものではありません。
前回実行時の子スレッドが終わっていなくても問題が起きないような作りにするのがベストだと思われます。


PATIO  2005-05-07 02:31:57  No: 57222

子プロセス側がきちんと外部からの終了に対応していない限り
基本的に安全かつ確実に終わらせる方法と言うのはありません。

問題になっている中断と言うのが起動側のアプリの方の話で、
起動先の子プロセスは放置でかまわないのであれば、ワーカースレッド側に
「子プロセスの終了の待ち合わせを中断する」仕組みが必要でしょう。
子プロセスの中断ではない点に注意してください。
単に待ち合わせを止めるだけの話なので子プロセスは放置になります。

例えば、WaitForMultiObjectで待ち合わせるようにしておいて
待ち合わせのハンドルに中断用のイベントハンドルも含めるようにしておけば、
メインスレッド側でイベントをONにすれば、ワーカースレッドは終了すると思います。但し、前述の通り、子プロセスは処理が終わって自力で終了するまで終わりません。
子プロセス側で起動される実行ファイルが二重起動をブロックしていれば、
二度目の実行で起動できずにエラー終了するかもしれませんが、
それに対してどうこうする手立てはないと思います。
素直に前回の処理が実行中なので処理できないというエラーにした方が素直ではないかと思います。

TerminateProcessを使えば、子プロセスを終了させることも出来ると思いますが、
TerminateProcessのHELPの解説でも触れられている通り、安全な終了方法ではありません。
子プロセス側は強制終了される為、本来行うべき終了処理があっても行われずに終了される可能性があります。

いずれにせよ、きちんと外部アプリケーションとの連携を考慮した形の設計でない限り、この辺の制御には限界があります。
子プロセス側で使用する実行ファイルを弄る事が出来ないのであれば、
仕様と言うことで納得するしかないと思います。


PATIO  2005-05-07 02:33:59  No: 57223

関数名を間違えていました。
WaitForMultiObjectではなくてWaitForMultipleObjectsでした。
失礼しました。


名古屋  2005-05-09 22:56:40  No: 57224

>ShellExecuteEx は対象のアプリを起動したら即座に処理を返します。
>対象のアプリが終了するまで待つようなことはしません。
>それを踏まえると、「計算処理待ち」というのは「計算処理が始まるのを待ってい>る状態」と解釈できますが、それでよろしいでしょうか?

  ご指摘のとおり、対象のアプリを起動したら即座に処理を返すため、
    WaitForSingleObject(test.hProcess,INFINITE);
  で計算処理を行うexeの処理が終了するまで待つようにしています。

>強制終了させる方法はありますが、望ましいものではありません。
  
  Windowsタスクマネージャのプロセスに、対象アプリが起動している
  ことが確認できるのですが、ここをみて、対象アプリが実行中であるか
  確認することはできるでしょうか?
  強制終了ができないのであれば、実行が終了するのを待ち、終了した時点で、
  中断を確定させるようにしたいのですが。
  (中断ボタン押下後、中断処理中の旨のメッセージを表示し、対象アプリ
  終了後、中断を確定させる。)

  なお、強制終了させた場合の問題点を教えてください。

  上記のことができなければ、PATIOさんのいわれるとおり
>素直に前回の処理が実行中なので処理できないというエラーにした方が素直ではな>いかと思います。
  とする他ないですね。
  二重起動をブロックしていますのでエラーがでてしまいますし。


名古屋  2005-05-10 01:45:43  No: 57225

今までの回答を参考に
以下のようにして、スレッド終了後、中止処理を終了させるようにしました。

大変参考になりました。ありがとうございました。

CWinThread* m_pThread   //スレッドへのポインタ
                          (NULLはスレッド起動してない)
//メイン処理
main
{
   m_pThread = NULL;

   m_pThread = AfxBeginThread( ThreadFunc , this ); //スレッド起動
   WaitForSingleObject( m_pThread->m_hThread, INFINITE);  
                                                    //スレッド終了を待つ
   m_pThread = NULL;

}

//スレッド処理
static UINT ThreadFunc( LPVOID pParam );
{
   スレッドでの処理
}

//中止ボタン押下時処理
void CLimitCurrentEXE::OnButton() 
{
   if(m_pThread != NULL)
   {
      WaitForSingleObject( m_pThread->m_hThread, INFINITE);
                   //スレッド終了を待つ(待っている間、メッセージ出す)
   }
   
   メイン終了処理
}


名古屋  2005-05-10 01:49:08  No: 57226

すみません。一応解決したのですが、以下の点だけ
教えてください。
できることであれば強制終了させたいので。

>強制終了させる方法はありますが、望ましいものではありません。
  
  強制終了させた場合の問題点を教えてください。
  また、よろしければ強制終了の方法を教えていただけたらと思います。


Ban  2005-05-10 02:04:53  No: 57227

> 強制終了させた場合の問題点を教えてください。
> また、よろしければ強制終了の方法を教えていただけたらと思います。

MSDN で TerminateProcess API を調べてください。
問題点も記載されています。


PATIO  2005-05-10 02:51:32  No: 57228

私がTerminateProcessを上げている所でHELPの解説でそういう記述がある事を上げているのですけれど。
まずは、HELP(MSDN)をよく読んでみてください。
必要な情報はたいていの場合、HELP(MSDN)で書かれている事が多いです。
HELPの調べ方を覚えるのも大切なことだと思いますよ。


名古屋  2005-05-10 19:24:16  No: 57229

>私がTerminateProcessを上げている所でHELPの解説でそういう
>記述がある事を上げているのですけれど。
>まずは、HELP(MSDN)をよく読んでみてください。
>必要な情報はたいていの場合、HELP(MSDN)で書かれている事が多いです。
>HELPの調べ方を覚えるのも大切なことだと思いますよ。

ご指摘ありがとうございます。
業務が切迫していましたので、ついここに頼りすぎていました。
HELPは詳細に記載があるかと思うのですがなかなか理解に苦しむ点
が多いですよね。
でも、そういった意味でもHELPで調べ慣れる必要があるのかもしれない
ですね。現状使えてないので...


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加