可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I want to find the title of the window which is currently active(having focus) using Window Script Host(WSH) because I want my WSH script to Sendkeys only If the desired window is active.
Note* I am not in a condition to use the alternative i.e activating the desired window before invoking sendkeys.
Any help is appreciated.
回答1:
Short answer: You can't. At least not without writing a COM wrapper for the relevant Windows API calls.
Can't you just use AppActivate
and check the result?
Set oShell = CreateObject("WScript.Shell")
If oShell.AppActivate "Untitled - Notepad" Then
oShell.SendKeys "Hello, world!"
End If
Long answer: To get the active window title, you need to call the Windows API GetWindowText
function and pass the GetForegroundWindow()
handle. VBScript and Windows Script Host don't support Windows API calls, so you'll need to write a COM wrapper around these functions, that you can then use in your script. Here're examples:
Get current active Window title in C
How do I get the title of the current active window using c#?
回答2:
You can make a COM object with GetForegroundWindow and GetWindowText.
Put following lines into wso.cls and store is a folder called wso on your desktop.
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
Then create a bat file in same folder called wso.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
To use in vbs after running bat file.
Set wso=CreateObject("WindowScriptingObject")
x = wso.ActiveWindow
msgbox x, , "vbs"
msgbox wso.windowtext(x), , "vbs"
The GUIDs used here are specific to this project. Do not use them for other purposes.
More info on what we are doing
http://social.msdn.microsoft.com/Forums/en-US/adcae113-4758-481a-a367-60d5d14d97d6/this-is-how-to-turn-vbs-and-js-files-into-exe-files-from-the-command-line-without-third-party-tools?forum=scripting
If you must do a per user install, use regasm to make a regfile instead of registering it. Then change all references to HKCR
to HKCU\Software\Classes
. Then merge with regedit /s regfile.reg
.
To move the file you need to run Regasm on it in it's new location. See command in bat file.
Will be posed at MS site of course for accurate historical purposes.
回答3:
This is an updated version for use. Previous answer is minimun needed for it to work.
This also replaces the answer here (appactivate between multiple internet explorer instances), as it didn't work for Windows 7 and later due to sendmail being a reserved name on those OSs.
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
回答4:
The batch file has to run without errors.
The first command makes the dll from the cls file. It will say Compilation Sucessfull. It expects the files to be in a folder called wso on your desktop.
The second command registers it per machine. You must be an admin to do this. If you are not an admin then you must generate a reg file, and change all HKEY_CURRENT_ROOT to HKEY_CURRENT_USER\Software\Classes.
To generate a regfile
"C:\Windows\Microsoft.NET\Framework\v4.0.30319\regasm" /regfile:"%userprofile%\desktop\wso\wso.reg" "%userprofile%\desktop\wso\wso.dll" /v
After editing wso.reg merge it with
regedit /m "%userprofile%\desktop\wso\wso.reg"
And you need to read the results of the commands.
Here is the script running showing hwnd, PID, and window title (and error code). Note how when script starts there is no active window for about two seconds (windows is waiting for your program to create one for it to make active. It only waits 2 seconds). Usually at program starts, but also other times, for short periods there will be no active window. You must trap this. Here's a script that does.
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
And this is what it looks like when run with CScript in a command prompt.
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>
----EDIT----
It's looks like you've been hit by a notepad bug when pasting from web pages from the funny spacing of the object name in the error message.
If using notepad to write it copy and paste into wordpad to check line breaks. Notepad totally ignores and hides carriage returns but other programs don't. Notepad only looks for line feeds. If coping from browser based documentation such as web pages and help systems sometimes stray carriage returns get invisibly inserted in notepad.