vb.net如何判断shell完成,或者等待shell完成

    Private Declare Function OpenProcess Lib "kernel32" (ByVal dwDesiredAccess As Long,ByVal bInheritHandle As Long,ByVal dwProcessId As Long) As Long
    Private Declare Function GetExitCodeProcess Lib "kernel32" (ByVal hProcess As Long,lpExitCode As Long) As Long
    Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
    Const PROCESS_QUERY_INFORMATION = &H400
    Const STILL_ALIVE = &H103

    Private Sub Command1_Click()
        Dim pid As Long
        pid = Shell("c:/a.bat",vbNormalFocus)
        hProcess = OpenProcess(PROCESS_QUERY_INFORMATION,pid)

        Do
            Call GetExitCodeProcess(hProcess,ExitCode)
            DoEvents()
        Loop While ExitCode = STILL_ALIVE
        Call CloseHandle(hProcess)
        MsgBox("运行结束")
    End Sub

VB启动/结束另一程序(Shell 等待程序运行结束)

VB 中,常以Shell指令来执行外部程式,然而它在Create该外部process 後,立刻就会回到vb 的下一行程式,无法做到等待该Process结束时,才执行下一行指令,或是说,无法得知该Process是否已结束,甚者,该Process执行到一半,又该如何中止其执行等等,这些都不是Shell指令所能控制的,因此我们需使API的帮助来完成。

第一个问题,如何等待shell所Create的process结束後才往後执行vb的程式。首先要知道的是,每个Process有唯一的一个ProcessID,这是OS给定的,用来区别每个 Process,这个Process ID(PID)主要可用来取得该Process相对应的一些资讯,然而要对该Process的控制,却大多透过 Process Handle(hProcess)。

VB Shell指令的传回值是PID,而非hProcess,所以我们需透过OpenProcess这个API来取得 hProcess而OpenProcess()的第一个叁数,指的是所取得的hProcess所具有的能力,像 PROCESS_QUERY_INFORMATION 便是让GetExitCode()可取得hProcess所指的process之状态,而PROCESS_TERMINATE,便是让TerminateProcess(hProcess..)的指令能够生效,也就是说,不同叁数设定,使hProcess所具有的权限、能力有所不同。

取得 hProcess後便可以使用WaitForSingleObject()来等待hProcess状态的改变,也就是说,它会等待 hProcess所指的process执行完,这个指令才结束,它第二个叁数所指的是 WaitForSingleObject()所要等待的时间(in milliseconds ),如果超过所指的时间,就TimeOut而结束WaitForSingleObject()的等待。若要它无限的等下去,就设定为INFIN99vE。

pid = Shell("C:/tools/spe3/pe2.exe",vbNormalFocus) 
hProcess = OpenProcess(PROCESS_QUERY_INFORMATION,pid) 
ExitEvent = WaitForSingleObject(hProcess,INFIN99vE) 
Call CloseHandle(hProcess)  
上例会无限等待shell指令create之process结束後,才再做後面的vb指令。有时觉得那会等太久,所以有第二个解决方式:


等process结束时再通知vb 就好,即:设定一个公用变数(isDone),当它变成True时代表Shell所Create的Process已结束。


当Process还在执行时,GetExitCodeProcess会传&H103给其第二个叁数,直到结束时才传另外的数值,如果程式正常结束,那Exitcode = 0,否则就得看它如何结束了。

或许有人在其他地方看到 loop的地方是Loop while Exitcode <> 0,那有一点危险,如果以这程子来看,您不是用F4来离开pe2而是用右上方 X 的结束dos window那麽,会因为ExitCode的值永远不会是0,而进入无穷的回圈。

    Dim pid As Long
    pid = Shell("C:/tools/spe3/pe2.exe",vbNormalFocus) 
    hProcess = OpenProcess(PROCESS_QUERY_INFORMATION,pid) 
    isDone = False 

    Do 
        Call GetExitCodeProcess(hProcess,ExitCode) 
        Debug.Print ExitCode 
        DoEvents 
    Loop While ExitCode = STILL_ALIVE 

    Call CloseHandle(hProcess) 
    isDone = True 

另外,如果您的shell所Create的程式,有视窗且为立刻Focus者,可另外用以下的方式:
    Dim pid As Long
    Dim hwnd5 As Long
    pid = Shell("c:/tools/spe3/pe2.exe",vbNormalFocus) 
    hwnd5 = GetForegroundWindow() 
    isDone = False 

    Do While IsWindow(hwnd5) 
        DoEvents 
    Loop 
    isDone = True 

而如何强迫shell所Create的process结束呢,那便是
    Dim aa As Long
    If hProcess <> 0 Then 
        aa = TerminateProcess(hProcess,3838) 
    End If 

hProcess便是先前的例子中所取得的那个Process Handle, 3838所指的是传给GetExitCodeProcess()中的第二叁数,这是我们任意给的,但最好不要是0,因为0一般是代表正常结束,当然这样设也不会有错。当然不可设&H103,以这个例子来看,如果程式正处於以下的LOOP
    Do 
        Call GetExitCodeProcess(hProcess,ExitCode) 
        Debug.Print ExitCode 
        DoEvents 
    Loop While ExitCode = STILL_ALIVE 

    Debug.print ExitCode 

而执行了 TerminateProcess(hProcess,3838)那会看到ExitCode = 3838。

然而,这个方式在win95没问题,在NT中,可能您要在OpenProcess()的第一个叁数要更改成 PROCESS_QUERY_INFORMATION Or PROCESS_TERMINATE 这样才能Work。不过良心的建议,非到最後关头,不要使用TerminateProcess(),因不正常的结束,往往许多程式结束前所要做的事都没有做,可能造成Resource的浪费,甚者,下次再执行某些程式时会有问题,例如:本人常使用MS-dos Shell Link 的方式执行一程式,透过Com port与大电脑的联结,如果Ms-dos Shell Link 不正常结束,下次再想Link时,会发现too Many Opens,这便是一例。


另外,有人使用Shell来执行.bat档,即:

    pid = Shell("c:/aa.bat",vbNormalFocus)
可是却遇上aa.bat结束了,但ms-dos的Window却仍活着,那可以用以下的方式来做

pid = Shell("c:/command.com /c c:/aa.bat",vbNormalFocus)


那是执行Command.com,而Command.com指定执行c:/aa.bat 而且结束时自动Close,所有程式如下:

    Private Declare Function OpenProcess Lib "kernel32" (ByVal dwDesiredAccess As Long,ByVal dwProcessId As Long) As Long
    Private Declare Function WaitForSingleObject Lib "kernel32" (ByVal hHandle As Long,ByVal dwMilliseconds As Long) As Long
    Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
    Private Declare Function GetExitCodeProcess Lib "kernel32" (ByVal hProcess As Long,lpExitCode As Long) As Long
    Private Declare Function TerminateProcess Lib "kernel32" (ByVal hProcess As Long,ByVal uExitCode As Long) As Long
    Private Declare Function GetForegroundWindow Lib "user32" () As Long
    Private Declare Function IsWindow Lib "user32" (ByVal hwnd As Long) As Long

    Const PROCESS_QUERY_INFORMATION = &H400
    Const STILL_ALIVE = &H103
    Const INFIN99vE = &HFFFF

    Private ExitCode As Long
    Private hProcess As Long
    Private isDone As Long

    Private Sub Command1_Click()
        Dim pid As Long
        pid = Shell("C:/tools/spe/pe2.exe",pid)
        isDone = False
        Do
            Call GetExitCodeProcess(hProcess,ExitCode)
            Debug.Print ExitCode
            DoEvents()
        Loop While ExitCode = STILL_ALIVE
        Call CloseHandle(hProcess)
        isDone = True
    End Sub

    Private Sub Command2_Click()
        Dim pid As Long
        Dim ExitEvent As Long
        pid = Shell("C:/tools/spe3/pe2.exe",pid)
        ExitEvent = WaitForSingleObject(hProcess,INFIN99vE)
        Call CloseHandle(hProcess)
    End Sub

    Private Sub Command3_Click()
        Dim aa As Long
        If hProcess <> 0 Then
            aa = TerminateProcess(hProcess,3838)
        End If

    End Sub

    Private Sub Command4_Click()
        Dim pid As Long
        Dim hwnd5 As Long
        pid = Shell("c:/tools/spe3/pe2.exe",vbNormalFocus)
        hwnd5 = GetForegroundWindow()
        isDone = False
        Do While IsWindow(hwnd5)
            DoEvents()
        Loop
        isDone = True
    End Sub

    Private Sub Command5_Click()
        Dim pid As Long
        'pid = Shell("c:/windows/command/xcopy c:/aa.bat a:",vbHide) 
        pid = Shell("c:/command.com /c c:/aa.bat",vbNormalFocus)
    End Sub

===================================================================================

===================================================================================

在使用shell后,如何等待此程序完成后,程序才继续执行.我们使用 shell 调用一个外部程序的时候,通常 vb(a) 会在调用之后继续下面的语句,而不管此 shell 程序执行完成没有.有时我们需要在此 shell 执行完成之后才继续,又当如何呢?请看源程:

    Public Declare Function OpenProcess Lib "kernel32" Alias "OpenProcess" (ByVal dwDesiredAccess As Long,ByVal dwProcessId As Long) As Long
    Public Declare Function WaitForSingleObject Lib "kernel32" Alias "WaitForSingleObject" (ByVal hHandle As Long,ByVal dwMilliseconds As Long) As Long
    Public Declare Function CloseHandle Lib "kernel32" Alias "CloseHandle" (ByVal hObject As Long) As Long

    Dim lngPId As Long
    Dim lngPHandle As Long
    lngPId = Shell("Notepad",vbNormalFocus)
    lngPHandle = OpenProcess(SYNCHRONIZE,lngpId)

    If lngPHandle <> 0 Then 
        Call WaitForSingleObject(lngPHandle,INFINITE) ' 无限等待, 直到程式结束
        Call CloseHandle(lngPHandle) 
    End If

需要注意的是,在 shell 程序未完成前,你的程序不能做任何事,请小心为之。


=============================================================================

=============================================================================

    Private Declare Function WaitForSingleObject Lib "kernel32" (ByVal hHandle As Long,ByVal dwMilliseconds As Long) As Long
    Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
    Private Declare Function ShellExecuteEx Lib "shell32.dll" Alias "ShellExecuteExA" (lpInfo As Any) As Long

    Private Type SHELLEXECUTEINFO
        cbSize  As Long
        fMask  As Long
        hwnd  As Long
        lpVerb  As String
        lpFile  As String
        lpParameters  As String
        lpDirectory  As String
        nShow  As Long
        hInstApp  As Long
       'Optional  members
        lpIDList  As Long
        lpClass    As String
        hkeyClass  As Long
        dwHotKey  As Long
        hIcon_OR_Monitor  As Long
        hProcess  As Long
    End Type

    Private Sub Form_Load()
        Dim si As SHELLEXECUTEINFO
        si.cbSize = Len(si)
        si.lpVerb = "open"
        si.lpFile = "notepad.exe"
        si.lpParameters = ""
        si.lpDirectory = ""
        si.nShow = 5            'SW_SHOW
        si.fMask = &H40      'SEE_MASK_NOCLOSEPROCESS
        ShellExecuteEx si
        If si.hProcess <> 0 Then
            WaitForSingleObject(si.hProcess,&HFFFFFFFF)      '  无限等待,  直到程式结束
            CloseHandle si.hProcess
            MsgBox "程序运行完毕!"
        End If
    End Sub

============================================

=============================================

shell命令一观:

shell "cmd /c dir",1'/c表示执行完即关闭窗口
shell "cmd /k dir",1'/k表示执行完停留
shell "cmd /c dir && pause",1'多条语句可用&&连接


关于cmd的具体用法可以在命令提示符下敲入cmd/?看看太多了,只列举一些典型的:
CMD [/A | /U] [/Q] [/D] [/E:ON | /E:OFF] [/F:ON | /F:OFF] [/V:ON | /V:OFF] [[/S] [/C | /K] string]


/C 执行字符串指定的命令然后终断
/K 执行字符串指定的命令但保留
/S 在 /C 或 /K 后修改字符串处理(见下)
/Q 关闭回应
/D 从注册表中停用执行 AutoRun 命令(见下)
/A 使向内部管道或文件命令的输出成为 ANSI
/U 使向内部管道或文件命令的输出成为 Unicode
/T:fg 设置前景/背景颜色(详细信息,请见 COLOR /?)
/E:ON 启用命令扩展(见下)
/E:OFF 停用命令扩展(见下)
/F:ON 启用文件和目录名称完成字符 (见下)
/F:OFF 停用文件和目录名称完成字符(见下)
/V:ON 将 ! 作为定界符启动延缓环境变量扩展。

如: /V:ON 会允许 !var! 在执行时允许 !var! 扩展变量 var。var 语法在输入时扩展变量,这与在一个 FOR 循环内不同。 /V:OFF 停用延缓的环境扩展。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Format[$] ( expr [ , fmt ] ) format 返回变体型 format$ 强制返回为文本 -------------------------------- 数字类型的格式化 --------------------------------     固定格式参数:     General Number 普通数字,如可以用来去掉千位分隔号     format$("100,1
VB6或者ASP 格式化时间为 MM/dd/yyyy 格式,竟然没有好的办法, Format 或者FormatDateTime 竟然结果和系统设置的区域语言的日期和时间格式相关。意思是尽管你用诸如 Format(Now, "MM/dd/yyyy"),如果系统的设置格式区域语言的日期和时间格式分隔符是"-",那他还会显示为 MM-dd-yyyy     只有拼凑: <%response.write
在项目中添加如下代码:新建窗口来显示异常信息。 Namespace My ‘全局错误处理,新的解决方案直接添加本ApplicationEvents.vb 到工程即可 ‘添加后还需要一个From用来显示错误。如果到这步还不会则需要先打好基础啦 ‘======================================================== ‘以下事件
转了这一篇文章,原来一直想用C#做k3的插件开发,vb没有C#用的爽呀,这篇文章写与2011年,看来我以前没有认真去找这个方法呀。 https://blog.csdn.net/chzjxgd/article/details/6176325 金蝶K3 BOS的插件官方是用VB6编写的,如果  能用.Net下的语言工具开发BOS插件是一件很愉快的事情,其中缘由不言而喻,而本文则是个人首创,实现在了用V
Sub 分列() ‘以空格为分隔符,连续空格只算1个。对所选中的单元格进行处理 Dim m As Range, tmpStr As String, s As String Dim x As Integer, y As Integer, subStr As String If MsgBox("确定要分列处理吗?请确定分列的数据会覆盖它后面的单元格!", _
  窗体代码 1 Private Sub Text1_OLEDragDrop(Data As DataObject, Effect As Long, Button As Integer, Shift As Integer, X As Single, Y As Single) 2 Dim path As String, hash As String 3 For Each fil
  Imports MySql.Data.MySqlClient Public Class Form1 ‘ GLOBAL DECLARATIONS Dim conString As String = "Server=localhost;Database=net2;Uid=root;Pwd=123456;" Dim con As New MySqlConnection
‘導入命名空間 Imports ADODB Imports Microsoft.Office.Interop   Private Sub A1() Dim Sql As String Dim Cnn As New ADODB.Connection Dim Rs As New ADODB.Recordset Dim S As String   S = "Provider=OraOLEDB.Oracl
Imports System.IO Imports System.Threading Imports System.Diagnostics Public Class Form1 Dim A(254) As String    Function ping(ByVal IP As Integer) As String Dim IPAddress As String IPAddress = "10.0.
VB运行EXE程序,并等待其运行结束 参考:https://blog.csdn.net/useway/article/details/5494084 Private Declare Function WaitForSingleObject Lib "kernel32" (ByVal hHandle As Long, ByVal dwMilliseconds As Long) As Long Pr
今天碰到一个问题,登陆的时候,如果不需要验证手机号为空,则不去验证手机号 因为登陆的时候所有的验证信息都存放在一个数组里 Dim CheckUserInfo() As String ={UserBirthday, SecEmail, UserMob, UserSex, RealNameFirst, RealName, CheckCardID, CheckCardType, Contactemail
在VB6.0中,数据访问接口有三种: 1、ActiveX数据对象(ADO) 2、远程数据对象(RDO) 3、数据访问对象(DAO) 1.使用ADO(ActiveX Data Objec,ActiveX数据对象)连接SQL Server 1)使用ADO控件连接 使用ADO控件的ConnectionString属性就可以连接SQL Server,该属性包含一个由分号分隔的argument=value语
注:大家如果没有VB6.0的安装文件,可自行百度一下下载,一般文件大小在200M左右的均为完整版的软件,可以使用。   特别提示:安装此软件的时候最好退出360杀毒软件(包括360安全卫士,电脑管家等,如果电脑上有这些软件的话),因为现如今的360杀毒软件直接会对VB6.0软件误报,这样的话就可能会在安装过程中被误报阻止而导致安装失败,或者是安装后缺乏很多必须的组件(其它的杀毒软件或安全卫士之类的
Private Sub Form_Load() Call conndb End Sub Private Function conndb() Dim cn As New ADODB.Connection Dim rs As New ADODB.Recordset Dim strCn, sql As String Dim db_host As String Dim db_user As String
  PPSM06S70:  Add  moddate  EDITSPRINTJOB:  MAX(TO_CHAR(ETRN.MODDATE, ‘yyyy/mm/dd/HH24:MI AM‘)) ACTUAL_SHIPDATE   4.Test Scenario (1) :Query SQL Test DN:8016578337 SELECT CTRN.TKCTID TRUCK_ID,        
  沒有出現CrystalReportViewer時,須安裝CRforVS_13_0. 新增1個數據集,新增1個數據表,添加二列,列名要和資料庫名一樣. 修改目標Framework 修改app.config, <startup >改成<startup useLegacyV2RuntimeActivationPolicy ="true">  CrystalReport1.rpt增加數據庫專家 在表單
Imports System.Threading Imports System Public Class Form1 Dim th1, th2 As Thread Public Sub Method1() Dim i As Integer For i = 1 To 100 If Me.Label1.BackColor =
Friend Const PROCESS_ALL_ACCESS = &H1F0FFF = 2035711 Friend Const PROCESS_VM_READ = &H10 Friend Const PROCESS_VM_WRITE = &H20 Friend Const PAGE_READONLY = &H2 Friend Const PAGE_READWRITE = &H4 Friend
以下代码随手写的 并没有大量测试 效率也有待提升 如果需要C#的请自行转换 Function SplitBytes(Data As Byte(), Delimiter As Byte()) As List(Of Byte()) Dim i = 0 Dim List As New List(Of Byte()) Dim bytes As New
Imports System.Data.SqlClient Public Class Form1 REM Public conn1 As SqlConnection = New SqlConnection("server=.; Integrated Security=False;Initial Catalog= mydatabase1; User ID= sa;password")