- ベストアンサー
VB6.0 SHELLで起動したプログラムを終了さしたいのですが
(1)メインプログラムから電卓を実行します。 Shell("C:\WINNT\system32\CALC.EXE", 1) (2)メインプログラムで電卓を終了させるにわ、どうすればいいのですか 教えてください。
- みんなの回答 (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
その他の回答 (4)
- TAGOSAKU7
- ベストアンサー率65% (276/422)
あっSendMessageの回答がでましたね。 で注意して欲しいのは、FindWindowを使う点です。 これはWindowのCaption、もしくはクラス名でWindowを探す点です。 クラス名は[CTRL]+[ALT]+[DEL]で起動中のアプリのクラス名の一覧が出てきます。 あれから参考にしてみてください。 電卓は複数起動が可能です。 Microsoftのサンプルでは、すでに電卓を起動してあったとき、先に起動してあったほうを終了させるおそれがあります。 よってFindWindowだけでWindowを探すには注意が必要です。 (それでもSendkeysよりは、かなりいいと思います。) もし自分で作成したソフトをShellで起動するなら、このままでも大丈夫かもしれませんが、そうでなければShellで起動した時のプロセスIDを取得して、起動中のアプリ達のプロセスIDと比較し、自分の起動したEXEかをチェックする必要があるのです。 今までのサンプルで大丈夫ならいいのですが、帰ってから締め切ってなかったら、またあとで書き込みます。 ちなみに書き込もうとしてるサンプルはVB6限定です。
お礼
ありがとうございました、いちどためさしていただきます。 また何かありましたらよろしくお願いします。
- todo36
- ベストアンサー率58% (728/1234)
API関数を使うなら...
- TAGOSAKU7
- ベストアンサー率65% (276/422)
Sendkeys は一番手っ取り早いです。 確かにHELPにも出ています。 しかし、どのVBのメーリングリストもSendkeysは使用しない方向でやっております。 それはWindowsにかかっている負荷の状況により、Sendkeysの処理が必ずしも一致するわけではないからです。 以前にサンプルを作ったのですが、どうやら自宅においたままになっているようなので、またあとで書き込みます。 キーワードはSendMessageです。
- bin-chan
- ベストアンサー率33% (1403/4213)
SendKeyで終了のキー操作情報を送信してやります。 たしかHELPのサンプルが電卓を終了させるものだったと記憶しています。
お礼
ありがとうございました、いちどためさしていただきます。 また何かありましたらよろしくお願いします。