您的位置:寻梦网首页编程乐园VB 编程Visual Basic 电子教程>VB Tips

正常结束由Shell所引发的Window 程式


        我们曾在使Shell指令具Wait功能的文章中提过,使用TerminateProcess()来结束一个由Shell所引发的Process,但也说过,这可能会有一些问题,如果说,所引发的是一般正常且单一的Window程式(如NotePad),那是有办法令之正常结束的,那便是使用PostMessage(hWnd, WM_CLOSE,0,0),令该Window结束。然而,Shell的传回值是Process ID而不是hWnd,所以要加一些动作来取得hWnd。我们可以用 GetForegroundWindow来做(如果该Shell是指定vbNormalFocus),另也可以使用FindWindow来做,但是,如果有两个NotePad在时,会取到那一个,实在不知。另外使EnumWindows来做,该Function用来巡行Top Level的Window,我们传入ProcessID当做EnumWindows的第二个参数,於是EnumWindowProcedure中的lParam便是该ProcessID,我们另外用tid = GetWindowThreadProcessId(hwnd, pid)来取得hWnd所属的ProcessID与我们传入的ProcessID(lParam)做比较,若相同,代表我们已找到所要的hWnd了。EnumWindows的用法请参考尝试寻找电脑中执行的程式.
        当然,这个程式的做法不是万能的,如果产生的Process又产生有好多个Window,我们结束的,可能只是其中之一,那程式可能要改一下,变成只要在EnumWindow Procedure中找到一个PID与Shell传回值的PID相同者,就使用PostMessage(hwnd, WM_CLOSE, 0,0)来结束之,但这也不一定就全然可行,如果产生的不是一个有Window的程式,那使用WM_CLOSE是没有用的,唯一能做的,就是使用TerminateProcess来强迫中断程式。以下程式在.BAS

以下程式在.BAS
Declare Function GetParent Lib "user32" (ByVal hwnd As Long) As Long
Declare Function EnumWindows Lib "user32" (ByVal lpEnumFunc As Long, ByVal lParam As Long) As Long
Declare Function GetWindowThreadProcessId Lib "user32" (ByVal hwnd As Long, lpdwProcessId As Long) As Long
Declare Function SetForegroundWindow Lib "user32" Alias "SetForegroundWindow" (ByVal hwnd As Long) As Long
Declare Function OpenProcess Lib "kernel32" _
(ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, _
ByVal dwProcessId As Long) As Long
Declare Function WaitForSingleObject Lib "kernel32" _
(ByVal hHandle As Long, ByVal dwMilliseconds As Long) As Long
Declare Function CloseHandle Lib "kernel32" _
(ByVal hObject As Long) As Long
Declare Function GetExitCodeProcess Lib "kernel32" _
(ByVal hProcess As Long, lpExitCode As Long) As Long
Declare Function TerminateProcess Lib "kernel32" _
(ByVal hProcess As Long, ByVal uExitCode As Long) As Long
Declare Function PostMessage Lib "user32" Alias "PostMessageA" _
(ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, _
ByVal lParam As Long) As Long

Public Const SYNCHRONIZE = &H100000
Public Const STILL_ALIVE = &H103
Public Const INFINITE = &HFFFF
Public Const WM_CLOSE = &H10
Public hWnd5 As Long
Function EnumWindowsProc(ByVal hwnd As Long, ByVal lParam As Long) As Boolean
Dim S As String
If GetParent(hwnd) = 0 Then
Dim tid As Long, pid As Long
tid = GetWindowThreadProcessId(hwnd, pid)
If pid = lParam Then
    hWnd5 = hwnd
    EnumWindowsProc = False
End If
End If
EnumWindowsProc = True ' 表示继续列举 hWnd
End Function

以下程序在.FORM
Option Explicit
Private ExitCode As Long
Private hProcess As Long
Private isDone As Long
Private Sub Command1_Click()
Dim pid As Long
pid = Shell("notepad.exe", vbNormalFocus)
Call EnumWindows(AddressOf EnumWindowsProc, pid) '设定hWnd5的值
hProcess = OpenProcess(SYNCHRONIZE , 0, pid)
isDone = False
Do
Call GetExitCodeProcess(hProcess, ExitCode)
DoEvents
Loop While ExitCode = STILL_ALIVE Or isDone
Call CloseHandle(hProcess)
isDone = True
Label1.Caption = "Over"
End Sub

Private Sub Command2_Click()
Dim i As Long
Call SetForegroundWindow(hWnd5)
Call PostMessage(hWnd5, WM_CLOSE, 0, 0)
End Sub

Private Sub Form_Unload(Cancel As Integer)
isDone = True
End Sub