【问题标题】:VBS not waiting for .Run command to finishVBS 不等待 .Run 命令完成
【发布时间】:2025-11-21 21:35:01
【问题描述】:

我有一个代码会自动打开个性化窗口,将主题更改为 Windows 7 Basic,然后关闭窗口。问题是,运行命令完成后窗口没有关闭。我使用的代码是这样的:

Set WshShell = WScript.CreateObject("WScript.Shell")

WshShell.Run "rundll32.exe %SystemRoot%\system32\shell32.dll,Control_RunDLL %SystemRoot%\system32\desk.cpl desk,@Themes /Action:OpenTheme /file:""C:\Windows\Resources\Ease of Access Themes\basic.theme""",1,true

WshShell.AppActivate("Desktop Properties") 
WshShell.Sendkeys "%FC"
WshShell.Sendkeys "{F4}"

现在,在最后加上“true”语句,是不是应该基本上等待这个命令完成,然后它会继续前进?因为如果我删除“true”语句以及最后的“1”,而是添加一个计时器,例如:

Set WshShell = WScript.CreateObject("WScript.Shell")

WshShell.Run "rundll32.exe %SystemRoot%\system32\shell32.dll,Control_RunDLL %SystemRoot%\system32\desk.cpl desk,@Themes /Action:OpenTheme /file:""C:\Windows\Resources\Ease of Access Themes\basic.theme"""


Wscript.Sleep 5000
WshShell.AppActivate("Desktop Properties") 
WshShell.Sendkeys "%FC"
WshShell.Sendkeys "{F4}"

只有在这里它会等待任务完成,然后关闭窗口。我究竟做错了什么!另外,有人可以准确解释“%FC”和“{F4}”的作用吗?我知道其中一个关闭了窗口,但我很难找到它们的确切含义。提前谢谢你!

【问题讨论】:

  • 如果将Run 方法的第三个参数设置为True,该方法只会在rundll32.exe 终止后返回,这会使脚本的其余部分毫无意义。您需要确定表明您的任务已完成的条件,并在继续之前检查该条件。
  • 我明白你的意思,但你怎么能终止它?因为它所做的只是将主题更改为某个文件,所以它基本上是单击一个文件并等待它加载。但是我确实发现这可行:Set WshShell = WScript.CreateObject("WScript.Shell") WshShell.Run "rundll32.exe %SystemRoot%\system32\shell32.dll,Control_RunDLL %SystemRoot%\system32\desk.cpl desk,@Themes /Action:OpenTheme /file:""C:\Windows\Resources\Ease of Access Themes\basic.theme""",1,true WScript.CreateObject("WScript.Shell").Run "taskkill /fi ""WINDOWTITLE eq Personalization""", 0, true
  • 为什么会这样?因为它等待rundll32 完成,然后窗口在完成后立即关闭。我不确定。
  • %FC 转换为按 Alt F C 键。% 是 Alt 的字符。 F 和 C 代表该特定窗口中文件和关闭的快捷方式。花括号用于您的示例中的 SendKeys 代码,它用于 F4 键。 WshShell.Sendkeys "%FC"WshShell.Sendkeys "{F4}"更多阅读:msdn.microsoft.com/en-us/library/…
  • 嗨,马特,感谢您的回复。我应该在发现后说,但我完全忘记了,但我确实发现了。不过还是谢谢!顺便说一句,您对我最初的问题有任何想法吗?就是想。如果没有,没问题,感谢您的帮助!

标签: vbscript cmd


【解决方案1】:

我希望我知道它的真正原因,但似乎脚本是按设计工作的。 RunDll32.exe 必须将处理传递给另一个进程,这就是脚本似乎无需等待即可继续执行的原因。我更新了脚本以证明发生了什么

Set WshShell = WScript.CreateObject("WScript.Shell")

msgbox (IsProcessRunning("rundll32.exe"))
WshShell.Run "rundll32.exe %SystemRoot%\system32\shell32.dll,Control_RunDLL %SystemRoot%\system32\desk.cpl desk,@Themes /Action:OpenTheme /file:""C:\Windows\Resources\Ease of Access Themes\basic.theme""",1,true
msgbox (IsProcessRunning("rundll32.exe"))
WshShell.AppActivate("Desktop Properties") 
WshShell.Sendkeys "%FC"
WshShell.Sendkeys "{F4}"

Function IsProcessRunning(pProcessName)
    ' Function will do a WMI query to determine if a the process pProcessName is currently
    ' running on the local computer. Returns True if detected. 
    Dim objWMIService
    Dim strWMIQuery

    strWMIQuery = "Select * From Win32_Process Where name Like '" & pProcessName & "'"
    Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2") 

    ' Run The query against the WMI for the local machine
    If (objWMIService.ExecQuery(strWMIQuery).Count > 0) Then
        IsProcessRunning = True
    Else
        IsProcessRunning = False
    End If
End Function

我添加了一个检查进程是否正在运行的函数。在您的命令之前一次,以证明它尚未运行。在rundll32.exe调用之后也证明它仍然没有运行。虽然在主题更改处理完成之前显示第二个 False 消息框似乎是多余的。

来自旧的 MS 知识库文章的片段:http://support.microsoft.com/kb/164787

Rundll 的工作原理

Rundll 执行以下步骤: 1.它解析命令行。 2. 它通过LoadLibrary() 加载指定的DLL。 3. 通过GetProcAddress()获取函数的地址。 4. 它调用函数,传递命令行尾部,即 . 5.函数返回时,Rundll.exe卸载DLL并退出。

希望有人可以修饰一下。

【讨论】:

  • 这有助于理解为什么它会以这种方式工作。不幸的是,我无法投票赞成您的帖子,但感谢您发布此帖子,它确实澄清了很多。我会继续调查。