如何使用VBScript在已经打开的CMD窗口中执行命令

3
我正在尝试自动化需要每天执行的备份。我有一个在CMD中运行的程序,在运行备份之前需要正确关闭它。 需要关闭的两个命令是: shutdown yes(确认操作)
然后该CMD窗口可以关闭,我已经编写了.bat文件以执行备份。
除了非常简单的情况外,我从未编写过VBScripts,如果我的问题不够清楚,我很抱歉。
思路如下 - 使用VBScript输入shutdown {Enter}和yes {Enter},然后关闭该CMD窗口,然后执行备份批处理文件,该文件已设置为在完成备份后启动CMD程序。
操作系统 - Windows XP Professional
谢谢!

谷歌Windows自动化。你的第一个问题将是找到cmd窗口。这个程序是否在这个窗口中运行?让它自己关闭可能会更容易。 - Tony Hopkinson
你是在启动那个“在CMD中运行的程序”来专门为备份准备文件吗?那是一个控制台程序吗?除了输入“shutdown”和“yes”之外,在整个过程中还有其他交互吗?根据这些问题的答案,可能可以使用管道输入。 - Andriy M
@AndriyM - 感谢您关注此事。不幸的是,我对控制台或管道完全不熟悉,但是运行在CMD窗口中的程序-数据库监视程序,它从多个客户端接收数据并将其记录在数据库中,并在客户端请求时检索数据。这两个命令是关闭此监视程序所需的唯一命令,从而避免在备份数据库之前损坏数据库。因此,如果管道方法仍然是解决方案-那么它是什么,我该如何使用它?再次感谢! - ikonerg
我可能过于仓促了,对于你的情况来说,那个管道方法可能不是一个好主意。如果它是一个交互式程序,在执行期间还应接受其他命令,那么你确实需要找其他解决方案。 - Andriy M
1个回答

3
您可以尝试通过将按键作为Windows消息发送到程序运行的CMD窗口来以编程方式输入命令。我不了解VBS,也许它有一个或多个函数映射到系统API函数PostMessage和/或SendMessage。如果有人发布了一个解释如何使用它们的答案,那就太好了。同时,我可以向您展示如何在批处理文件中使用一个名为SendMessage实用程序来使用此方法。基本上,该实用程序允许您像这样向任意窗口发送任意Windows消息:
SendMessage.exe <i>target_specification</i> /message:<i>value</i> /wparam:<i>value</i> /lparam:<i>value</i> 

稍后我会讲解target_specification位,其他参数包括:

  • /message:value – the message being sent, specified by code. In you case it would be either of these:

    /message:WM_CHAR
    /message:258
    /message:0x0102
    

    which all specify the WM_CHAR message.

  • /wparam:value – for the WM_CHAR message, this one should be the code of the keystroke being sent.

    In your case, since your commands consist of ASCII characters only, all the codes would match the ASCII codes of the corresponding characters. Therefore, you can use an ASCII chart to convert the characters in your commands. The s, for instance would be

    /wparam:115
    

    and h

    /wparam:104
    

    and so on.

    Note that you will also need to be sending the Enter key presses too. According to the ASCII control code chart, it would be

    /wparam:13
    
  • /lparam:value – you can see from the WM_CHAR's manual page that the LPARAM parameter is actually supposed to carry multiple pieces of information as a single numeric value. However, for your specific case it would be enough to just memorise that this parameter should be specified simply as

    /lparam:1
    
现在进入目标规范部分。这可能有点棘手。从工具网页的描述中,您将了解到有不同的指定目标窗口的方式。但并非每种方法都适合您。
例如,您可以尝试通过进程名称指定目标:
/processname:<i>name_of_your_executable</i>

然而,如果您不是直接调用程序,而是在批处理文件中调用它,那么程序将不会在自己的窗口中运行,而是会借用托管CMD会话的窗口,因此这种方法可能无法使用。 如果确实是这样调用程序的话,您可以尝试使用窗口标题来指定目标:
/windowtitle:<i>window_title</i>

这里需要注意的唯一一点是,标题必须唯一地标识所需的窗口,否则按键将发送到与指定标题匹配的所有窗口。您可以尝试使用批处理中的title命令(在调用程序之前设置它)来使标题唯一化。
因此,总结一下,以下是完整备份脚本(批处理脚本)的示例,假设目标窗口将由其标题指定:
@ECHO OFF
:: s
SendMessage.exe /windowtitle:"My Title" /message:WM_CHAR /wparam:115 /lparam:1
:: h
SendMessage.exe /windowtitle:"My Title" /message:WM_CHAR /wparam:104 /lparam:1
:: u
SendMessage.exe /windowtitle:"My Title" /message:WM_CHAR /wparam:117 /lparam:1
:: t
SendMessage.exe /windowtitle:"My Title" /message:WM_CHAR /wparam:116 /lparam:1
:: d
SendMessage.exe /windowtitle:"My Title" /message:WM_CHAR /wparam:100 /lparam:1
:: o
SendMessage.exe /windowtitle:"My Title" /message:WM_CHAR /wparam:111 /lparam:1
:: w
SendMessage.exe /windowtitle:"My Title" /message:WM_CHAR /wparam:119 /lparam:1
:: n
SendMessage.exe /windowtitle:"My Title" /message:WM_CHAR /wparam:110 /lparam:1
:: ENTER
SendMessage.exe /windowtitle:"My Title" /message:WM_CHAR /wparam:13 /lparam:1

:: y
SendMessage.exe /windowtitle:"My Title" /message:WM_CHAR /wparam:121 /lparam:1
:: e
SendMessage.exe /windowtitle:"My Title" /message:WM_CHAR /wparam:101 /lparam:1
:: s
SendMessage.exe /windowtitle:"My Title" /message:WM_CHAR /wparam:115 /lparam:1
:: ENTER
SendMessage.exe /windowtitle:"My Title" /message:WM_CHAR /wparam:13 /lparam:1

:: wait for some time (~3 sec) till the program shuts down, if necessary
PING -n 4 localhost 1>NUL

:: proceed with the back-up
...

哇,非常感谢!我现在可以看到离完成这个任务已经很接近了!我按照你上面告诉我的做了一切,对WM_CHAR有了很多了解。但是,出于某种原因,当我使用.bat命令SendMessage.exe /windowtitle:"My Title" /message:WM_CHAR /wparam:115 /lparam:1时,在窗口中根本没有输入任何字母。但是如果我键入SendMessage.exe /windowtitle:"My Title" /message:16,我会收到一个警告消息,告诉我即将强制关闭窗口。 - ikonerg
从那个我得出结论,窗口的定位不是问题 - 它可以很好地找到它,但看起来当使用WM_CHAR命令时我做错了什么。从查看Microsoft网站上的WM_CHAR,我读到了一些关于它使用UTF-16字符编码的内容,所以这让我想也许我应该使用一些不同的数字来表示字母? - ikonerg
抱歉,昨晚没能看到你的回复。目前没有什么可以告诉你的。我在 Windows 7 x64 下进行了测试。我尝试在一个“干净”的 cmd.exe 会话上使用 SendMessage(即我只是运行了 cmd.exe,设置了标题,然后发送了 WM_CHARs),以及在一个带有 ftp.exe 的 CMD 会话中使用 SendMessage(即从 cmd.exe 中打开 ftp.exe,它在同一窗口内启动了自己的会话,然后我发送了 WM_CHARs)。两个测试都成功了。我不知道,也许你正在使用一个 DOS (实际 DOS) 程序,它无法接收任何 WM_CHARs。恐怕我无法在我的 Win 7 上验证这一点。 - Andriy M
我打算自己尝试这种方法,既是为了自己的学习,也是为了能够尝试并为您提供另一种脚本的选择,只是不能保证很快就会发生。 - Andriy M
非常感谢您的回复!是的,这是DOS程序,在TaskMgr中运行我的DOS程序时,我有ntvdm.exe运行。我注意到在网上有几篇关于使用虚拟输入来运行DOS程序的帖子,但那些帖子对我来说太高深了。他们谈论C++,而我从未接触过C++,并且据我所知,在批处理文件中没有使用Keybd_event的用途。Keybd_event是我理解可以解决问题的东西。然后有一个VBS文件可以完成向任何DOS程序发送键的任务 - 对我来说这是一个黑暗的森林!- http://www.devx.com/vb2themax/Tip/19094 - ikonerg
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接