You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何让Excel VBA等待IE中打开的文档打印完成再执行?

问题描述

我需要打印从网页下载后在IE浏览器中打开的文档(该文档页面没有检查元素选项),目前使用SendKeys可以实现打印操作,但当文件较大时,会弹出“打印进行中”的进度窗口。Application.Wait无法确定合适的等待时长,请教如何让宏暂停执行直至打印进度完成?

当前使用的打印函数

Function Sample(tet As Variant)
Dim IE_Tab As SHDocVw.InternetExplorer, ie As InternetExplorer
Dim HTML_Doc As MSHTML.HTMLDocument
Dim SH_Win As SHDocVw.ShellWindows, sh As Object
Dim T_Str As String
Set SH_Win = New SHDocVw.ShellWindows

 For Each IE_Tab In SH_Win
     T_Str = IE_Tab.LocationURL
       If T_Str = tet Then
         Application.Wait (Now + TimeValue("00:00:05"))
         Set sh = CreateObject("WScript.Shell")
         'this command just populates the print dialog box, it worked fine only if i print an web page here iam trying to print a document opened as IE
         IE_Tab.ExecWB OLECMDID_PRINT, OLECMDEXECOPT_DODEFAULT, 2, 0
         sh.AppActivate "Print"
         Application.Wait (Now + TimeValue("00:00:02"))
         sh.SendKeys "c", 1
         Application.Wait (Now + TimeValue("00:00:02"))
        sh.SendKeys ("{ENTER}")
         IE_Tab.Quit
            Exit For
     End If
Next
End Function

相关窗口截图

  • 打印窗口:
    Print window
  • 打印进度窗口:
    Progress

解决方案

固定时长的Application.Wait确实不靠谱,尤其是处理大文件时,我们可以通过Windows API函数来检测“打印进行中”窗口的存在,循环等待直到该窗口消失,再继续执行后续代码。

步骤1:添加API声明

在VBA模块的最顶部添加以下API函数声明,用来查找系统窗口:

Private Declare PtrSafe Function FindWindow Lib "user32" Alias "FindWindowA" _
    (ByVal lpClassName As String, ByVal lpWindowName As String) As LongPtr

Private Declare PtrSafe Function FindWindowEx Lib "user32" Alias "FindWindowExA" _
    (ByVal hWnd1 As LongPtr, ByVal hWnd2 As LongPtr, ByVal lpsz1 As String, _
    ByVal lpsz2 As String) As LongPtr

注:如果使用32位Office,去掉PtrSafe并将LongPtr替换为Long即可。

步骤2:修改打印函数,添加智能等待逻辑

我们在发送打印确认的Enter键后,加入循环检测逻辑,直到“打印进行中”窗口消失再关闭IE标签。修改后的函数如下:

Function Sample(tet As Variant)
    Dim IE_Tab As SHDocVw.InternetExplorer, ie As InternetExplorer
    Dim HTML_Doc As MSHTML.HTMLDocument
    Dim SH_Win As SHDocVw.ShellWindows, sh As Object
    Dim T_Str As String
    Dim progressWnd As LongPtr
    
    Set SH_Win = New SHDocVw.ShellWindows

    For Each IE_Tab In SH_Win
        T_Str = IE_Tab.LocationURL
        If T_Str = tet Then
            Application.Wait (Now + TimeValue("00:00:05"))
            Set sh = CreateObject("WScript.Shell")
            
            ' 触发打印对话框
            IE_Tab.ExecWB OLECMDID_PRINT, OLECMDEXECOPT_DODEFAULT, 2, 0
            sh.AppActivate "Print"
            Application.Wait (Now + TimeValue("00:00:02"))
            sh.SendKeys "c", 1
            Application.Wait (Now + TimeValue("00:00:02"))
            sh.SendKeys "{ENTER}"
            
            ' 循环等待打印进度窗口消失
            Do
                ' 根据你的进度窗口标题查找窗口,标题不对请自行修改
                progressWnd = FindWindow(vbNullString, "打印进行中")
                ' 释放CPU资源,避免程序假死
                DoEvents
                ' 每500毫秒检测一次
                Application.Wait (Now + TimeValue("00:00:00.5"))
            Loop While progressWnd <> 0
            
            ' 打印完成后关闭IE标签
            IE_Tab.Quit
            Exit For
        End If
    Next
End Function

关键说明

  • 如果你的打印进度窗口标题不是“打印进行中”,请替换FindWindow函数的第二个参数为实际窗口标题。
  • DoEvents能让Excel在等待期间响应其他操作,避免出现程序无响应的情况。
  • 500毫秒的检测间隔可以根据需要调整,既保证响应速度,又不会过度占用系统资源。

内容的提问来源于stack exchange,提问作者arun v

火山引擎 最新活动