 |
这是一个特别常见的问题,相信很多人都会遇到。
如果使用VB.Net,Shell函数增加了一个参数表示是否等待。例子:
Dim sysPath as String
SysPath = System.Environment.GetFolderPath _
(Environment.SpecialFolder.System)
Shell(sysPath & "\notepad.exe", _
AppWinStyle.NormalFocus, True)
但如果使用VB 5.0/6.0,就比较麻烦了,一般实现这种等待的方法有四种:
一种是利用是利用Win32 API的FindWindow函数。该函数可以搜索指定标题或类的窗口,你可以在调用第一个可执行文件后用FindWindow函数去找指定的窗口,如果找到了,就说明第一个文件还未运行完,等待,直到用FindWindow函数找不到指定窗口,就可以调用第二个文件。这种方法简单,但有个毛病,就是如果满足条件的窗口不只一个,比如用户打开了两个有相同类或标题的窗口(一个是VB程序打开的,而另一个可能是用户自行打开的),那么除非用户关闭这两个窗口,否则VB程序不会继续运行。比如Wise Install生成的安装程序就有这个毛病,它在安装过程中可能会用NotePad打开ReadMe文件,等用户看完ReadMe文件关闭窗口后继续安装,但如果用户此时用NotePad打开了其他文件,安装程序就会继续等待,应为FindWindow函数找到了NotePad窗口,可实际上这个窗口跟安装程序毫无关系。
第二种是利用Windows 95新增加的命令Start。这个命令可以调用Windows程序,通常用在批文件中。它有一个/w开关,在被调用的程序继续运行结束之前等待。比如,你要调用的三个可执行文件为Command1、Command2和Command3,你可以构造一个批文件如下:
Start/w Command1
Start/w Command2
Start/w Command3
这个方法可以保证三个按既定顺序运行,但VB程序不能知道什么时候该批文件执行完毕。
第三种方法是利用Windows API的OpenProcess和CloseHandle函数来实现对被调用软件的检测:
1) 在VB中新建一个标准EXE工程;
2) 在Form1中声明OpenProcess和 CloseHandle 这两个Windows API 函数;
Private Declare Function OpenProcess Lib "kernel32" (ByVal dwDesiredAccess As Long, ByVal
bInheritHandle As Long, ByVal dwProcessId As Long) As Long
Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
3) 然后编写下面的函数:
Function IsRunning(ByVal ProgramID) As Boolean ' 传入进程标识ID
Dim hProgram As Long '被检测的程序进程句柄
hProgram = OpenProcess(0, False, ProgramID)
If Not hProgram = 0 Then
IsRunning = True
Else
IsRunning = False
End If
CloseHandle hProgram
End Function
4) 在Form_Click()中加入代码:
Sub Form_Click()
Dim X
Me.Caption = "开始运行"
X = Shell("NotePad.EXE", 1)
While IsRunning(X)
DoEvents
Wend
Me.Caption = "结束运行"
End Sub
第四种方法是利用Win32 API的CreateProcess函数和WaitForSingleObject函数来进行这一工作。它的原理比较复杂,在此只介绍如何使用。首先建立一个模块(module),然后输入以下语句:
Option Explicit
Type STARTUPINFO
cb As Long
lpReserved As String
lpDesktop As String
lpTitle As String
dwX As Long
dwY As Long
dwXSize As Long
dwYSize As Long
dwXCountChars As Long
dwYCountChars As Long
dwFillAttribute As Long
dwFlags As Long
wShowWindow As Integer
cbReserved2 As Integer
lpReserved2 As Long
hStdInput As Long
hStdOutput As Long
hStdError As Long
End Type
Type PROCESS_INFORMATION
hProcess As Long
hThread As Long
dwProcessID As Long
dwThreadID As Long
End Type
Global Const NORMAL_PRIORITY_CLASS = &H20&
Global Const INFINITE = -1&
Declare Function CloseHandle Lib "kernel32" (hObject As Long) As Boolean
Declare Function WaitForSingleObject Lib "kernel32" (ByVal hHandle As Long, ByVal dwMilliseconds As Long) As Long
Declare Function CreateProcessA Lib "kernel32" ( _
ByVal lpApplicationName As Long, _
ByVal lpCommandLine As String, ByVal lpProcessAttributes As Long, ByVal _
lpThreadAttributes As Long, ByVal bInheritHandles As Long, ByVal _
dwCreationFlags As Long, ByVal lpEnvironment As Long, ByVal _
lpCurrentDirectory As Long, lpStartupInfo As STARTUPINFO, _
lpProcessInformation As PROCESS_INFORMATION) As Long
Public Sub ShellAndWait(cmdline$)
Dim NameOfProc As PROCESS_INFORMATION
Dim NameStart As STARTUPINFO
Dim X As Long
NameStart.cb = Len(NameStart)
X = CreateProcessA(0&, cmdline$, 0&, 0&, 1&, NORMAL_PRIORITY_CLASS, _
0&, 0&, NameStart, NameOfProc)
X = WaitForSingleObject(NameOfProc.hProcess, INFINITE)
X = CloseHandle(NameOfProc.hProcess)
End Sub
建立一个窗体,并放一个命令按钮(Command1)在其上。在Command1_Click事件中输入以下内容:
Private Sub Command1_Click()
Dim AppToLaunch As String
AppToLaunch = "c:\win95\notepad.exe"
ShellAndWait AppToLaunch
End Sub
运行该程序,按下Command1,就会调用NotePad,在NotePad运行完毕之前,VB程序不会继续执行。你可以在程序中使用ShellAndWait来代替Shell命令。
此问题由李海回答。
附加关键字:编程, 源程序, programming, source code, Visual Basic, VB, 其他方面, 。
|