• ベストアンサー

VB6.0 SHELLで起動したプログラムを終了さしたいのですが

(1)メインプログラムから電卓を実行します。  Shell("C:\WINNT\system32\CALC.EXE", 1) (2)メインプログラムで電卓を終了させるにわ、どうすればいいのですか  教えてください。

質問者が選んだベストアンサー

  • ベストアンサー
  • TAGOSAKU7
  • ベストアンサー率65% (276/422)
回答No.5

(今会社なのですが、、、)サンプルありました。奥深く眠ってました。 Microsoftの終了方法と、定数が違いますが、こちらでも終了ができます。 コメントを見たら、処理の流れがわかると思いますが、処理の流れを記します。 Shellで電卓を起動します。Shell関数は起動したアプリのプロセスIDを返します。 次に Call EnumWindows(AddressOf EnumWinProc, 0&)を実行します。 これはたった一文で、FOR文/DO~LOOP文を使用してませんが、EnumWinProc関数内を何度も実行します。実行回数はWindowsに存在するハンドルの数だけ実行されます。 そしてその関数内で電卓のプロセスと同じハンドルを探し、電卓に終了の命令を送ってます。 EnumWinProc内を詳しく説明します。 GetParentが'0'ゼロの時、未処理としています。 これは何を意味するかというと、フォームだけでなく、フォームの中に存在するボタン、リストボックス、ラベル、それぞれのコントロールにハンドルが存在します。 しかしフォームとその中のコントロールには親子の関係があります。 GetParent(子のハンドル)の時 → '0以外'の数値を返します。基本的にフォーム(親)のハンドルのを返します。 GetParent(フォームのハンドル)の時 → '0'を返します。親が存在しないためです。 電卓にも多くのボタンが存在してます。そのボタンのハンドルはチェックする必要がないのでGoto文で未処理にさせています。必要なのは電卓本体が必要で、GetParentで0を返すものが、チェックの候補となるわけです。 あとは電卓のプロセスと比較し、一致するハンドルを取得するだけです。 Option Explicit ' ウィンドウのプロセスIDとスレッドIDを取得する関数の宣言 Private Declare Function GetWindowThreadProcessId Lib "user32.dll" _   (ByVal hwnd As Long, lpdwProcessId As Long) As Long '親ハンドルを取得する関数の宣言 Private Declare Function GetParent Lib "user32" _   (ByVal hwnd As Long) As Long 'ウィンドウを列挙する関数の宣言 Public Declare Function EnumWindows Lib "user32" _   (ByVal lpEnumFunc As Long, ByVal lParam As Long) As Long 'ウィンドウにメッセージ定数を送る関数の宣言 Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" _   (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Long) As Long Public Const WM_CLOSE = &H10 '見つかったウィンドウハンドル Private FindWinWnd As Long '探すべきプロセス Private FindPrs   As Long Sub Main()   Dim lngSts As Long   '初期化を行う   FindWinWnd = 0   FindPrs = 0   'とりあえず電卓を起動と同時に、電卓のプロセスを得る   FindPrs = Shell("Calc.exe")      'プロセス=0のとき起動失敗   If FindPrs = 0 Then     MsgBox "電卓の起動失敗"     GoTo PGMEND   End If      'Windowsに存在する全部のハンドルから、電卓のプロセスの一緒のハンドルを探す   Call EnumWindows(AddressOf EnumWinProc, 0&)      '電卓を終了します。   If (FindWinWnd <> 0&) Then     MsgBox "電卓が見つかりませた。終了します。"     Call SendMessage(FindWinWnd, WM_CLOSE, 0&, 0&)   Else     MsgBox "電卓が見つかりませんでした。"   End If    PGMEND: End Sub 'Windowsの全ハンドルを得ることができる関数 '内部処理は、 '(1)指定のプロセスを探す '(2)見つかったプロセスのハンドルを記憶 Public Function EnumWinProc(ByVal hwnd As Long, lParam As Long) As Boolean   Dim lngTrd As Long 'スレッド   Dim lngPrs As Long 'プロセス      'Trueの間は、Windowsに存在するハンドルを最後まで取得しようとする   EnumWinProc = True      '子ウィンドウは未処理   If Not (GetParent(ByVal hwnd) = 0) Then GoTo PGMEND      'スレッドとプロセスを取得する   lngTrd = GetWindowThreadProcessId(hwnd, lngPrs)      '同じプロセスだとしたら   If lngPrs = FindPrs Then     '取得してきたハンドルを記憶     FindWinWnd = hwnd     'これ以上のハンドルは取得しないでもいいので、Falseをセット     EnumWinProc = False   End If    PGMEND: End Function

chiba-masaru
質問者

お礼

ありがとうございました、いちどためさしていただきます。 また何かありましたらよろしくお願いします。

その他の回答 (4)

  • TAGOSAKU7
  • ベストアンサー率65% (276/422)
回答No.4

あっSendMessageの回答がでましたね。 で注意して欲しいのは、FindWindowを使う点です。 これはWindowのCaption、もしくはクラス名でWindowを探す点です。 クラス名は[CTRL]+[ALT]+[DEL]で起動中のアプリのクラス名の一覧が出てきます。 あれから参考にしてみてください。 電卓は複数起動が可能です。 Microsoftのサンプルでは、すでに電卓を起動してあったとき、先に起動してあったほうを終了させるおそれがあります。 よってFindWindowだけでWindowを探すには注意が必要です。 (それでもSendkeysよりは、かなりいいと思います。) もし自分で作成したソフトをShellで起動するなら、このままでも大丈夫かもしれませんが、そうでなければShellで起動した時のプロセスIDを取得して、起動中のアプリ達のプロセスIDと比較し、自分の起動したEXEかをチェックする必要があるのです。 今までのサンプルで大丈夫ならいいのですが、帰ってから締め切ってなかったら、またあとで書き込みます。 ちなみに書き込もうとしてるサンプルはVB6限定です。

chiba-masaru
質問者

お礼

ありがとうございました、いちどためさしていただきます。 また何かありましたらよろしくお願いします。

  • todo36
  • ベストアンサー率58% (728/1234)
回答No.3

API関数を使うなら...

参考URL:
http://www.microsoft.com/JAPAN/support/kb/articles/j044/1/40.htm
  • TAGOSAKU7
  • ベストアンサー率65% (276/422)
回答No.2

Sendkeys は一番手っ取り早いです。 確かにHELPにも出ています。 しかし、どのVBのメーリングリストもSendkeysは使用しない方向でやっております。 それはWindowsにかかっている負荷の状況により、Sendkeysの処理が必ずしも一致するわけではないからです。 以前にサンプルを作ったのですが、どうやら自宅においたままになっているようなので、またあとで書き込みます。 キーワードはSendMessageです。

  • bin-chan
  • ベストアンサー率33% (1403/4213)
回答No.1

SendKeyで終了のキー操作情報を送信してやります。 たしかHELPのサンプルが電卓を終了させるものだったと記憶しています。

関連するQ&A