【发布时间】:2014-12-08 02:55:48
【问题描述】:
我想使用 Window Script Host(WSH) 查找当前处于活动状态(具有焦点)的窗口的标题,因为我希望我的 WSH 脚本仅在所需窗口处于活动状态时才发送键。
注意*我无法使用替代方法,即在调用 sendkeys 之前激活所需的窗口。
感谢任何帮助。
【问题讨论】:
我想使用 Window Script Host(WSH) 查找当前处于活动状态(具有焦点)的窗口的标题,因为我希望我的 WSH 脚本仅在所需窗口处于活动状态时才发送键。
注意*我无法使用替代方法,即在调用 sendkeys 之前激活所需的窗口。
感谢任何帮助。
【问题讨论】:
简答:你不能。至少要为相关的 Windows API 调用编写 COM 包装器。
你不能只使用AppActivate 并检查结果吗?
Set oShell = CreateObject("WScript.Shell")
If oShell.AppActivate "Untitled - Notepad" Then
oShell.SendKeys "Hello, world!"
End If
长答案: 要获取活动窗口标题,您需要调用 Windows API GetWindowText 函数并传递 GetForegroundWindow() 句柄。 VBScript 和 Windows Script Host 不支持 Windows API 调用,因此您需要围绕这些函数编写一个 COM 包装器,然后您可以在脚本中使用它。以下是示例:
Get current active Window title in C
How do I get the title of the current active window using c#?
【讨论】:
AppActivate 和 SendKeys 的 func 参数周围缺少 ()。 (没有它们我收到了语法错误)
您可以使用 GetForegroundWindow 和 GetWindowText 创建一个 COM 对象。
将以下行放入 wso.cls 中,然后在您的桌面上存储一个名为 wso 的文件夹。
Imports System
Imports System.Runtime.InteropServices
Imports Microsoft.Win32
Namespace WindowScriptingObject
<Guid("7448E08D-ED0F-4E23-B528-91937BB41756"), _
InterfaceType(ComInterfaceType.InterfaceIsIDispatch)> _
Public Interface _WindowScriptingObject
<DispId(1)> Function ActiveWindow() As Integer
<DispId(2)> Function WindowText(ByVal hWnd As Integer) As String
End Interface
<Guid("B146BF9E-78FC-4DB0-ABFE-9FF026B43E4D"), _
ClassInterface(ClassInterfaceType.None), _
ProgId("WindowScriptingObject")> Public Class WindowScriptingObject
Implements _WindowScriptingObject
Public WindowScriptingObject()
Public Declare Auto Function GetForegroundWindow Lib "user32" Alias "GetForegroundWindow"() As Integer
Public Declare Auto Function GetWindowText Lib "user32.dll" (ByVal hwnd As Int32, <Out()> ByVal lpString As System.Text.StringBuilder, ByVal cch As Int32) As Int32
Public Function ActiveWindow() As Integer Implements _WindowScriptingObject.ActiveWindow
ActiveWindow=GetForegroundWindow()
End Function
Public Function WindowText(hwnd as Integer) As String Implements _WindowScriptingObject.WindowText
on error resume next
Dim b As New System.Text.StringBuilder(ChrW(0), 512)
Dim ret = GetWindowText(hWnd, b, b.Capacity)
WindowText = b.tostring
End Function
End Class
End Namespace
然后在名为 wso.bat 的同一文件夹中创建一个 bat 文件。
"C:\Windows\Microsoft.NET\Framework\v4.0.30319\vbc.exe" /target:library /out:"%userprofile%\desktop\wso\wso.dll" "%userprofile%\desktop\wso\wso.cls" /verbose
"C:\Windows\Microsoft.NET\Framework\v4.0.30319\regasm" /codebase "%userprofile%\desktop\wso\wso.dll" /tlb:"%userprofile%\desktop\wso\wso.tlb" /v
If /i "%cmdcmdline:~0,6%"=="cmd /c" pause
运行bat文件后在vbs中使用。
Set wso=CreateObject("WindowScriptingObject")
x = wso.ActiveWindow
msgbox x, , "vbs"
msgbox wso.windowtext(x), , "vbs"
此处使用的 GUID 特定于该项目。不要将它们用于其他目的。
更多关于我们正在做什么的信息
如果您必须按用户安装,请使用 regasm 创建一个 regfile 而不是注册它。然后将所有对HKCR 的引用更改为HKCU\Software\Classes。然后与regedit /s regfile.reg合并。
要移动文件,您需要在其新位置运行 Regasm。请参阅 bat 文件中的命令。
为了准确的历史目的,当然会在 MS 网站上摆姿势。
【讨论】:
这是一个更新版本供使用。以前的答案是它工作所需的最低限度。
这也替换了此处的答案 (appactivate between multiple internet explorer instances),因为它不适用于 Windows 7 及更高版本,因为 sendmail 是这些操作系统上的保留名称。
Imports System
Imports System.Runtime.InteropServices
Imports Microsoft.Win32
Namespace WindowScriptingObject
<Guid("7448E08D-ED0F-4E23-B528-91937BB41756"), _
InterfaceType(ComInterfaceType.InterfaceIsIDispatch)> _
Public Interface _WindowScriptingObject
<DispId(1)> Function ActiveWindow() As UInteger
<DispId(2)> Function WindowText(ByVal hWnd As UInteger) As String
<DispId(3)> Function WindowPID(ByVal hWnd As UInteger) As UInteger
End Interface
<Guid("B146BF9E-78FC-4DB0-ABFE-9FF026B43E4D"), _
ClassInterface(ClassInterfaceType.None), _
ProgId("WindowScriptingObject")> Public Class WindowScriptingObject
Implements _WindowScriptingObject
Public WindowScriptingObject()
Public Declare Auto Function GetForegroundWindow Lib "user32" Alias "GetForegroundWindow"() As UInteger
Public Declare Auto Function GetWindowText Lib "user32.dll" (ByVal hwnd As Int32, <Out()> ByVal lpString As System.Text.StringBuilder, ByVal cch As Int32) As Int32
Public Declare Auto Function GetWindowThreadProcessId Lib "user32" Alias "GetWindowThreadProcessId" (ByVal hwnd As UInteger, ByRef lpdwProcessId As UInteger) As UInteger
Public Function ActiveWindow() As UInteger Implements _WindowScriptingObject.ActiveWindow
ActiveWindow = GetForegroundWindow()
If err.lastdllerror <> 0 then
Dim tmp as uinteger = err.lastdllerror and &h80070000
err.raise(tmp, "WindowSystemObject.GetForegroundWindow", "Type net helpmsg " & err.lastdllerror & " in a command prompt for help")
Exit Function
End If
End Function
Public Function WindowText(hwnd as UInteger) As String Implements _WindowScriptingObject.WindowText
Dim b As New System.Text.StringBuilder(ChrW(0), 512)
Dim ret as uinteger = GetWindowText(hWnd, b, b.Capacity)
If err.lastdllerror <> 0 then
Dim tmp as uinteger = err.lastdllerror and &h80070000
WindowText = ""
err.raise(tmp, "WindowSystemObject.GetWindowText", "Type net helpmsg " & err.lastdllerror & " in a command prompt for help")
Exit Function
End If
WindowText = b.tostring
End Function
Public Function WindowPID(HWnd as UInteger) As UInteger Implements _WindowScriptingObject.WindowPID
Dim X as UInteger
Dim M as UInteger = 1
X=GetWindowThreadProcessID(HWnd,M)
If err.lastdllerror <> 0 then
Dim tmp as uinteger = err.lastdllerror and &h80070000
WindowPID = 0
err.raise(tmp, "WindowSystemObject.GetWindowThreadProcessID", "Type net helpmsg " & err.lastdllerror & " in a command prompt for help")
Exit Function
End If
WindowPID = M
End Function
End Class
End Namespace
【讨论】:
批处理文件必须无错误地运行。
第一个命令从 cls 文件生成 dll。它会说编译成功。它希望文件位于您桌面上名为 wso 的文件夹中。
第二个命令在每台机器上注册它。您必须是管理员才能执行此操作。如果您不是管理员,则必须生成一个 reg 文件,并将所有 HKEY_CURRENT_ROOT 更改为 HKEY_CURRENT_USER\Software\Classes。
生成一个regfile
"C:\Windows\Microsoft.NET\Framework\v4.0.30319\regasm" /regfile:"%userprofile%\desktop\wso\wso.reg" "%userprofile%\desktop\wso\wso.dll" /v
编辑 wso.reg 后将其与
regedit /m "%userprofile%\desktop\wso\wso.reg"
你需要读取命令的结果。
这是运行的脚本,显示 hwnd、PID 和窗口标题(和错误代码)。请注意,当脚本启动时,大约两秒钟内没有活动窗口(Windows 正在等待您的程序创建一个以使其处于活动状态。它只等待 2 秒钟)。通常在程序启动时,但也有其他时间,短时间内不会有活动窗口。你必须抓住这个。这是一个脚本。
On error resume next
Set wso=CreateObject("WindowScriptingObject")
Do
x = wso.ActiveWindow
wscript.echo x
wscript.echo wso.windowtext(x)
wscript.echo (err.number)
err.clear
wscript.echo wso.windowpid(x)
wscript.echo (err.number)
err.clear
wscript.sleep 1000
Loop
这就是在命令提示符下使用 CScript 运行时的样子。
C:\Users\User>cscript "C:\Users\User\Desktop\ActiveWindow.vbs"
Microsoft (R) Windows Script Host Version 5.7
Copyright (C) Microsoft Corporation. All rights reserved.
-2147024809
-2147024809
3344366
Administrator: Command Prompt - cscript "C:\Users\User\Desktop\ActiveWin
dow.vbs"
0
972
0
3344366
Administrator: Command Prompt - cscript "C:\Users\User\Desktop\ActiveWin
dow.vbs"
0
972
0
3344366
1312854
vbscript - How to find the window Title of Active(foreground) window using Windo
w Script Host - - Windows Internet Explorer
0
4724
0
1312854
vbscript - How to find the window Title of Active(foreground) window using Windo
w Script Host - - Windows Internet Explorer
0
4724
0
3344366
Administrator: Command Prompt - cscript "C:\Users\User\Desktop\ActiveWin
dow.vbs"
0
972
0
^C
C:\Users\User>
----编辑----
从错误消息中对象名称的有趣间距从网页粘贴时,您似乎遇到了记事本错误。
如果使用记事本编写,请复制并粘贴到写字板中以检查换行符。记事本完全忽略并隐藏回车,但其他程序不会。记事本只查找换行符。如果处理基于浏览器的文档(例如网页和帮助系统),有时会在记事本中不可见地插入回车。
【讨论】: