1

是的。复杂。
前提:
我正在运行一个需要通过 FTP 检索信息的 Access 数据库。它使用 WScriptExec 对象运行 ftp.exe 并读取 stdOut 以确定创建目录的日期和时间(名称是格式为“d.yymmdd.hhmmss”的日期和时间,所以我只是向ls d.*服务器发送一个)。该代码有效,除了我希望窗口不显示或至少隐藏得更快。
目标:
通过找到它的句柄来查找和操作 WScriptExec 窗口(我天生就有 ProcessID,这显然毫无价值)。不,我不想/不能在此应用程序中使用 .Run 并输出到文件。我以后可能需要像这样操作一个窗口,并且想知道如何在没有“使用其他方法”之类的解决方法的情况下进行操作。
我试过的:
-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从这个链接。我尝试过的一切都返回 0。我对其进行了修改以弹出它找到的每个窗口,但没有看到听起来正确的窗口标题。所以我假设标题不是 WScriptExec 命令提示符窗口中显示的标题。
- GetForegroundWindow。返回我的 Access DB 窗口,即使在AppActivate objExec.ProcessID.

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

4

2 回答 2

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 工作原理的更多信息,可以通过快速的 google 搜索为您提供大量信息。

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

于 2014-01-09T18:23:30.727 回答
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 APISleep命令 obvi。

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

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

于 2013-06-19T11:46:23.870 回答