使用FindWindow在VBA中隐藏WScriptExec窗口

时间:2013-06-18 13:43:34

标签: vba wsh findwindow

是。复杂。
前提:
我正在运行Access数据库,需要通过FTP检索信息。它使用WScriptExec对象运行ftp.exe并读取stdOut以确定创建目录的日期和时间(名称是'd.yymmdd.hhmmss'格式的日期和时间,所以我只发送ls d.*到服务器)。代码工作,但我希望窗口不显示或至少更快隐藏 目的:
通过查找它的句柄来查找和操作WScriptExec窗口(我本身就有ProcessID,显然它毫无价值)。不,我不想/不能在这个应用程序中使用。运行并输出到文件。我可能需要稍后操作这样的窗口,并且想知道如何在没有“使用其他方法”的解决方法的情况下进行操作。
我试过的:
  - FindWindow("Console,MSDOS,pretty much any made up class I could think of since I don't know class types", "C:\WINDOWS\system32\ftp.exe, C:\WINDOWS\system32\cmd.exe, ftp.exe, cmd.exe, pretty much every window title you can imagine")所有这些都与另一个参数中的vbNullString有关。对于我尝试过的所有内容,我都会获得0分   - FindWindowLike from this link。为我所尝试的一切获得0回报。我修改它以弹出它找到的每个窗口,并没有看到听起来正确的窗口标题。所以我假设标题不是WScriptExec命令提示符窗口中显示的标题   - GetForegroundWindow。即使在AppActivate objExec.ProcessID之后,也会返回我的Access数据库窗口。

仅供参考,我如何调用WScriptExec对象:
Set objExec = objShell.Exec("cmd /c ftp -n ftp.server.location")(我尝试过没有cmd /c;两者都有效)

2 个答案:

答案 0 :(得分:3)

这个问题可能有点旧,但我认为这个答案仍然可以提供帮助。 (使用Excel VBA测试,无法使用Access进行测试)

非常类似于usncahill的答案,但不是睡觉或等待窗口加载它将继续循环并查找hwnd并在找到后立即执行。

我的下面脚本从Exec对象获取ProcessID以找到窗口的Hwnd。使用Hwnd,您可以设置窗口的显示状态。

从我使用Excel 2007 VBA进行测试,在大多数情况下我甚至都没有看到窗口......在某些情况下,它可能会在几毫秒内显示,但只会出现快速闪烁或闪烁......注意:我有使用SW_MINIMIZE比使用SW_HIDE更好的结果,但你可以玩它。

我添加了TestRoutine Sub以显示如何使用'HideWindow'功能的示例。 'HideWindow'函数使用'GetHwndFromProcess'函数从ProcessID获取窗口hwnd。

将以下内容放入模块......

Option Explicit
'   ShowWindow() Commands
Public Const SW_HIDE = 0
Public Const SW_MINIMIZE = 6
'GetWindow Constants
Public Const GW_CHILD = 5
Public Const GW_HWNDFIRST = 0
Public Const GW_HWNDLAST = 1
Public Const GW_HWNDNEXT = 2
Public Const GW_HWNDPREV = 3
Public Const GW_OWNER = 4
'   API Functions
Public Declare Function ShowWindow Lib "user32" (ByVal hwnd As Long, ByVal nCmdShow As Long) As Long
Public Declare Function GetWindow Lib "user32" (ByVal hwnd As Long, ByVal wCmd As Long) As Long
Public Declare Function GetDesktopWindow Lib "user32" () As Long
Public Declare Function GetWindowThreadProcessId Lib "user32" (ByVal hwnd As Long, lpdwProcessId As Long) As Long


Sub TestRoutine()
    Dim objShell As Object
    Dim oExec As Object
    Dim strResults As String

    Set objShell = CreateObject("WScript.Shell")
    Set oExec = objShell.Exec("CMD /K")
    Call HideWindow(oExec.ProcessID)

    With oExec
        .StdIn.WriteLine "Ping 127.0.0.1"
        .StdIn.WriteLine "ipconfig /all"
        .StdIn.WriteLine "exit"
        Do Until .StdOut.AtEndOfStream
            strResults = strResults & vbCrLf & .StdOut.ReadLine
            DoEvents
        Loop
    End With
    Set oExec = Nothing
    Debug.Print strResults
End Sub


Function HideWindow(iProcessID)
    Dim lngWinHwnd As Long
    Do
        lngWinHwnd = GetHwndFromProcess(CLng(iProcessID))
        DoEvents
    Loop While lngWinHwnd = 0
    HideWindow = ShowWindow(lngWinHwnd, SW_MINIMIZE)
End Function

Function GetHwndFromProcess(p_lngProcessId As Long) As Long
    Dim lngDesktop As Long
    Dim lngChild As Long
    Dim lngChildProcessID As Long
    On Error Resume Next
    lngDesktop = GetDesktopWindow()
    lngChild = GetWindow(lngDesktop, GW_CHILD)
    Do While lngChild <> 0
        Call GetWindowThreadProcessId(lngChild, lngChildProcessID)
        If lngChildProcessID = p_lngProcessId Then
            GetHwndFromProcess = lngChild
            Exit Do
        End If
        lngChild = GetWindow(lngChild, GW_HWNDNEXT)
    Loop
    On Error GoTo 0
End Function

ShowWindow功能: http://msdn.microsoft.com/en-us/library/windows/desktop/ms633548%28v=vs.85%29.aspx

GetWindow功能: http://msdn.microsoft.com/en-us/library/windows/desktop/ms633515%28v=vs.85%29.aspx

GetDesktopWindow功能: http://msdn.microsoft.com/en-us/library/windows/desktop/ms633504%28v=vs.85%29.aspx

GetWindowThreadProcessId函数: http://msdn.microsoft.com/en-us/library/windows/desktop/ms633522%28v=vs.85%29.aspx

如果您需要有关API如何运作的更多信息,快速谷歌搜索将为您提供大量信息。

我希望这可以帮助......谢谢你。

答案 1 :(得分:0)

FindWindow("ConsoleWindowClass", vbNullString)如果给出足够的延迟以允许窗口加载,则有效。

以下代码允许用户隐藏WScriptExec对象:

Public Declare Function ShowWindow Lib "user32" (ByVal hWnd As Long, ByVal nCmdShow As Long) As Long
Public Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long

Dim objShell As Object, objExec As Object
Dim lngWnd As Long

Set objShell = CreateObject("Wscript.Shell")
Set objExec = objShell.Exec("ftp -n server.location.com")

Pause 0.01
lngWnd = FindWindow("ConsoleWindowClass", vbNullString)
ShowWindow lngWnd, 0
MsgBox lngWnd

其中Pause是我用来延迟程序的代码,值以秒为单位。您可以使用windows API Sleep命令,而不是obvi。

此方法的成功测试是弹出消息并且控制台窗口不再可见。感谢@mehow的帮助:)

我见过很多人试图在我的搜索中隐藏他们的WScriptExec对象窗口。如果您可以将它们指向此解决方案,那么它至少会帮助那些希望窗口隐藏以进行长时间活动的人。 问题的真正答案是使用API​​手动加载控制台进程。