vbs中实现启动两个应用程序,一直等到其中一个程序结束,然后关闭另一个?

问:
嗨,脚本专家!这是我想要完成的任务:我想要用一个脚本启动两个可执行文件。第一个应用程序关闭后,我想让这个脚本关闭第二个应用程序,然后退出。如何完成上述任务?

-- MK

答:
您好,MK。您知道,这是我们喜欢的那种类型的问题。为什么?因为它听起来确实很复杂很棘手。如果有人想找我们做什么事,我们就可以说“您知道,我正在尝试编写这样一个脚本:它能够启动两个应用程序,等到第一个关闭后,然后自动关闭第二个。”然后他们肯定会说“噢,很抱歉。很显然,你们很忙”,然后就不找我们了。

当然,他们不知道,这只是听起来很困难。其实,它的难度也就相当于下面这个脚本而已:

代码如下:

strComputer = "." 
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2:Win32_Process")

errResult = objWMIService.Create("calc.exe", null, null, intCalcID) 
errResult = objWMIService.Create("notepad.exe", null, null, intNotepadID)

Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")

Set colProcesses = objWMIService.ExecNotificationQuery _ 
    ("Select * From __InstanceDeletionEvent " _  
            & "Within 1 Where TargetInstance ISA 'Win32_Process'")

Do Until i = 999 
    Set objProcess = colProcesses.NextEvent 
    If objProcess.TargetInstance.ProcessID = intCalcID Then 
        Exit Do 
    End If 
Loop

Set colProcesses = objWMIService.ExecQuery _ 
    ("Select * from Win32_Process Where ProcessID = " & intNotepadID)

For Each objProcess in colProcesses 
    objProcess.Terminate() 
Next

真的,请相信我们:您了解了脚本所完成的工作后,这其实就变得相当简单了。我们首先连接到计算机上的 WMI 服务,具体地说,绑定到 Win32_Process 类。这就是我们现在要做的:

Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2:Win32_Process")

然后,我们使用 Create 方法创建两个新进程:Calc.exe 和 Notepad.exe。对于每个新进程,我们使用与下面这行代码类似的代码:

errResult = objWMIService.Create("calc.exe", null, null, intCalcID)

我们剩下要做的只是调用跟有下列内容的 Create 方法:

• 可执行文件的名称(可能需要指定应用程序的完全路径名称,视您的计算机的设置而定)。

• 一对 Null 参数。使用这两个参数,我们可以为应用程序指定不同的工作文件夹和配置某些其他启动选项。在本示例代码中,我们不需要考虑这些事情,因此我们只是将参数值设置为 Null。

• 起“输出参数”作用的变量(名称为 intCalcID)。创建这些进程后,分配给进程的 ProcessID 号也分配给这些输出参数变量。

最终结果是我们启动“计算器”,并且变量 intCalcID 中包含分配给“计算器”实例的进程 ID。然后,我们启动“记事本”,并且变量 intNotepadID 中包含分配给“记事本”实例的 ProcessID。这就是启动两个应用程序并且跟踪它们的方法。

下一步我们要做的是,嗯,基本没什么了:我们要此脚本暂停,直到关闭“计算器”。要完成此任务,我们重新连接到 WMI 服务,然后使用 ExecNotificationQuery 监视任何删除的进程。我们需要重新连接到 WMI 服务是因为在脚本的开始我们只是连接到 Win32_Process 类;因此,对象引用 (objWMIService) 只是引用此类。我们需要连接到“通用”WMI 服务,所以我们只是重新使用对象引用 objWMIService 并进行新连接:

Set colProcesses = objWMIService.ExecNotificationQuery _
    ("Select * From __InstanceDeletionEvent " _ 
            & "Within 1 Where TargetInstance ISA 'Win32_Process'")

这么做的原因何在?每次删除一个进程,都要生成一个 __InstanceDeletionEvent 类实例。我们要检查每个实例,看这些实例的进程 ID 是否为目标 ID,也就是分配给 intCalcID 的 ID。如果删除的进程具有不同的 ID,则它不是“计算器”实例;在这种情况下,脚本将恢复监视。如果删除的进程具有与 intCalcID 相同的 ID,则它一定是“计算器”实例(因为进程 ID 必须是唯一的)。在这种情况下,我们要停止监视,然后关闭“记事本”。

下面是实际执行监视的代码:

Do Until i = 999
    Set objProcess = colProcesses.NextEvent
    If objProcess.TargetInstance.ProcessID = intCalcID Then
        Exit Do
    End If
Loop

这里我们做的是设置一个循环,该循环一直运行到变量 i 等于 999。现在,事实是变量 i 将始终不等于 999;这只是个小技巧,确保循环一直运行到“计算器”关闭。(我们如何知道变量 i 将始终不等于 999?是这样,我们没有为 i 赋值;因此,它取默认值 0。因为我们从未对该值进行任何更改,所以 i 始终为 0,因此将始终不等于 999。)

在循环中,我们使用此行代码等待下一个删除的进程:

Set objProcess = colProcesses.NextEvent

每次删除进程我们都检查 ProcessID 与分配给“计算器”的进程 ID 是否相符。如果相符,我们则使用 Exit Do 命令断开循环,继续脚本。如果不具有相同的 ID,则我们只需继续循环,等待下一个删除的进程。(正如我们上面所说的,i 将始终不等于 999,但是没关系:使用 Exit Do 命令就可以脱离循环。)

注意。我们发现,我们有点草草掠过事件监视的整个思路。如果您对诸如 __InstanceDeletionEvent 和 colProcesses.NextEvent 的内容有点糊涂,请参阅脚本专家网络广播防患于未然:WMI 事件简介(英文)。

现在,我们只需要终止我们启动的“记事本”实例。要完成此任务,我们使用此 WMI 查询检索具有分配给“记事本”的进程 ID 的所有进程的集合:

Set colProcesses = objWMIService.ExecQuery _
    ("Select * from Win32_Process Where ProcessID = " & intNotepadID)

获得此集合后,我们使用此代码块在整个进程集(只有一个进程)中循环,然后使用 Terminate 方法关闭应用程序:

For Each objProcess in colProcesses
    objProcess.Terminate()
Next

顺便说一句,此方法既适用于远程计算机也适用本地计算机;只需将变量 strComputer 的值更改为远程计算机的名称。但是,要记住,在 Windows XP 和 Windows Server 2003 中,在远程计算机上启动的进程是在不可见的窗口中运行的;它们在屏幕上不可见。这意味着,处理远程计算机时,对于不需要任何用户交互的应用程序,此方法很有用;而对于确实需要用户干预的应用程序,此方法远不及其他方法有用(实际上完全没用)。

(0)

相关推荐

  • vbs中实现启动两个应用程序,一直等到其中一个程序结束,然后关闭另一个?

    问: 嗨,脚本专家!这是我想要完成的任务:我想要用一个脚本启动两个可执行文件.第一个应用程序关闭后,我想让这个脚本关闭第二个应用程序,然后退出.如何完成上述任务? -- MK 答: 您好,MK.您知道,这是我们喜欢的那种类型的问题.为什么?因为它听起来确实很复杂很棘手.如果有人想找我们做什么事,我们就可以说"您知道,我正在尝试编写这样一个脚本:它能够启动两个应用程序,等到第一个关闭后,然后自动关闭第二个."然后他们肯定会说"噢,很抱歉.很显然,你们很忙",然后就不找

  • perl中子程序中参数的两种引用(传递)方式介绍

    下面是一个例子: 复制代码 代码如下: use strict;#这里是两个数组my @i =('1','2','3');my @j =('a','b','c'); #在进行处理之前,我们把他们先打印出来,看一看他们的样子print "In main program before calling subroutine:i="."@i\n";print "In main program before calling subroutine:j=".&q

  • Android 中启动自己另一个程序的activity如何实现

    Android 中启动自己另一个程序的activity如何实现 可以使用action,举例: 1. 比如建立activity4,我们对它的AndroidManifest.xml修改一下  <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:<a href="http://lib.csdn.net/base/android" rel="external no

  • Android编程实现在一个程序中启动另一个程序的方法

    本文实例讲述了Android编程实现在一个程序中启动另一个程序的方法.分享给大家供大家参考,具体如下: Android 开发有时需要在一个应用中启动另一个应用,比如Launcher加载所有的已安装的程序的列表,当点击图标时可以启动另一个应用. 一般我们知道了另一个应用的包名和MainActivity的名字之后便可以直接通过如下代码来启动: Intent intent = new Intent(Intent.ACTION_MAIN); intent.addCategory(Intent.CATEG

  • VBS中Run和Exec的区别

    Set ws = CreateObject("WScript.Shell") '这里创建一个对象引用,以便在以下示例代码中使用. 'Demon注:这个变量名怎么这么猥琐(WS) 语法:(常识(Demon注:常识这个词我喜欢):作为过程使用时,不要加括号,否则出现编译器错误(参数唯一或没有时加括号不会出错,但建议不要加)) 复制代码 代码如下: ws.Run(strCommand, [intWindowStyle], [bWaitOnReturn]) [Set objExec =] ws

  • 深入Android中BroadcastReceiver的两种注册方式(静态和动态)详解

    今天我们一起来探讨下安卓中BroadcastReceiver组件以及详细分析下它的两种注册方式. BroadcastReceiver也就是"广播接收者"的意思,顾名思义,它就是用来接收来自系统和应用中的广播.在Android系统中,广播体现在方方面面,例如当开机完成后系统会产生一条广播,接收到这条广播就能实现开机启动服务的功能:当网络状态改变时系统会产生一条广播,接收到这条广播就能及时地做出提示和保存数据等操作:当电池电量改变时,系统会产生一条广播,接收到这条广播就能在电量低时告知用户

  • Java多线程中线程的两种创建方式及比较代码示例

    1.线程的概念:线程(thread)是指一个任务从头至尾的执行流,线程提供一个运行任务的机制,对于java而言,一个程序中可以并发的执行多个线程,这些线程可以在多处理器系统上同时运行.当程序作为一个应用程序运行时,java解释器为main()方法启动一个线程. 2.并行与并发: (1)并发:在单处理器系统中,多个线程共享CPU时间,而操作系统负责调度及分配资源给它们. (2)并行:在多处理器系统中,多个处理器可以同时运行多个线程,这些线程在同一时间可以同时运行,而不同于并发,只能多个线程共享CP

  • 解决docker run时候启动两个占有不同端口的问题

    问题描述: 在执行docker run -p 19918:19918/tcp -v /etc/localtime:/etc/localtime时候后 docker ps查看有启动19918和另一个端口,并在注册中心未发现执行程序. 问题分析: 启动的另一端口为之前配置的,猜测为run时执行了刚刚build的项目外执行了之前的容器. 解决方式: docker images查看容器,删除相同的以及两个执行出的端口容器.再次执行显示成功! 总结: 命名规范,及时清除不必要的容器. 补充知识:docke

  • docker容器内要启动两个进程时Dockerfile的实现代码

    近期想做一个cron定时任务的docker,在Dockerfile中做如下定义 FROM library/alpine:latest RUN apk --update add rsync openssh bash VOLUME ["/data"] ADD start.sh / CMD ["/bin/bash","/start.sh"] 在start.sh中用crontab 加载定时任务run.cron,然后启动crond: /usr/bin/cr

  • 在VBS中定义字节数组Byte()介绍

    晚上在 QQ 上看到昵称为"乱码"的好友回答了搜搜问问里一个问题: 在VBS中有办法定义字节数组么? 在VBS中有办法定义字节数组么?就是字节子类型数组(VarType是8209的那种)注意不是VB! 但是回答实在是不堪入目,连别人问什么都没搞懂,而且那人居然还满意,真不知道他在想什么. 闲来没事,我来简单回答一下.首先要搞清楚别人在问什么,VBS 是弱类型脚本语言,只有一种数据类型,称为 Variant,但是 Variant 可以进一步分为几种子类型,这里不展开,详见<VBSc

随机推荐