Vb.net 从webbrowser打印两次

Vb.net 从webbrowser打印两次,vb.net,Vb.net,当我尝试多次打印COM webbrowser时,我遇到了问题。 要复制问题,请执行以下操作: 1) 创建新的“Windows窗体”项目 2) 将COM引用添加到“Microsoft Internet控件” 3) 将webbrowser控件“webbrowser1”和按钮“button1”添加到表单(来自工具箱) 4) 确保您有文件“c:\index.html” 5) 添加此代码 Option Explicit On Imports System.IO Imports System.Reflec

当我尝试多次打印COM webbrowser时,我遇到了问题。
要复制问题,请执行以下操作:

1) 创建新的“Windows窗体”项目
2) 将COM引用添加到“Microsoft Internet控件”
3) 将webbrowser控件“webbrowser1”和按钮“button1”添加到表单(来自工具箱)
4) 确保您有文件“c:\index.html”
5) 添加此代码

Option Explicit On

Imports System.IO
Imports System.Reflection
Imports System.Diagnostics.Process
Imports System.Runtime.InteropServices
Imports SHDocVw

Public Class Form1
Dim WithEvents p As New PrintHTML
Dim htmlfilename As String

Private Sub Form1_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
    p = Nothing
End Sub

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    htmlfilename = "c:\index.html"
    WebBrowser1.Navigate(htmlfilename)
End Sub

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    p.PrintHTMLDocument(htmlfilename)
End Sub
End Class

Public Class PrintHTML

Dim documentLoaded As Boolean = False
Dim documentPrinted As Boolean = False

Public Sub PrintHTMLDocument(ByVal htmlfilename As String)

    Dim ie As New InternetExplorer
    AddHandler DirectCast(ie, InternetExplorer).PrintTemplateTeardown, AddressOf PrintedCB
    AddHandler DirectCast(ie, InternetExplorer).DocumentComplete, AddressOf LoadedCB

    ie.Navigate(htmlfilename)
    While Not documentLoaded AndAlso ie.QueryStatusWB(OLECMDID.OLECMDID_PRINT) <> OLECMDF.OLECMDF_ENABLED
        Application.DoEvents()
        Threading.Thread.Sleep(100)
    End While

    Try
        ie.ExecWB(OLECMDID.OLECMDID_PRINT, OLECMDEXECOPT.OLECMDEXECOPT_DONTPROMPTUSER, vbNull, vbNull)
        While Not documentPrinted
            Application.DoEvents()
            Threading.Thread.Sleep(100)
        End While
    Catch ex As Exception
        Debug.Print(ex.Message)
    End Try
End Sub

Private Sub LoadedCB(ByVal obj As Object, ByRef url As Object)
    documentLoaded = True
End Sub

Private Sub PrintedCB(ByVal obj As Object)
    documentPrinted = True
End Sub
End Class
选项显式打开
导入System.IO
输入系统。反射
导入System.Diagnostics.Process
导入System.Runtime.InteropServices
进口SHDocVw
公开课表格1
使用事件p作为新的打印HTML进行Dim
将htmlfilename设置为字符串
私有子表单1_FormClosing(ByVal sender作为对象,ByVal e作为System.Windows.Forms.FormClosingEventArgs)处理Me.FormClosing
p=无
端接头
私有子表单1_Load(ByVal发送方作为System.Object,ByVal e作为System.EventArgs)处理MyBase.Load
htmlfilename=“c:\index.html”
WebBrowser1.Navigate(htmlfilename)
端接头
私有子按钮1\u单击(ByVal sender作为System.Object,ByVal e作为System.EventArgs)处理按钮1。单击
p、 PrintHTMLDocument(htmlfilename)
端接头
末级
公共类PrintHTML
Dim documentLoaded As Boolean=False
打印为布尔值=False的文档
公共子PrintHTMLDocument(ByVal htmlfilename作为字符串)
Dim ie成为新的InternetExplorer
AddHandler DirectCast(即InternetExplorer).PrintTemplateTeardown,PrintedCB的地址
AddHandler DirectCast(即InternetExplorer).DocumentComplete,LoadedCB的地址
ie.Navigate(htmlfilename)
在未加载文档且启用ie.QueryStatusWB(OLECMDID.OLECMDID_打印)OLECMDF.OLECMDF_时
Application.DoEvents()
线程。线程。睡眠(100)
结束时
尝试
ie.ExecWB(OLECMDID.OLECMDID_打印,OLECMDEXECOPT.OLECMDEXECOPT_dontComputser,vbNull,vbNull)
而不是打印文档
Application.DoEvents()
线程。线程。睡眠(100)
结束时
特例
调试.打印(例如消息)
结束尝试
端接头
私有子加载的cb(ByVal obj作为对象,ByRef url作为对象)
documentLoaded=True
端接头
私有子打印的CB(ByVal obj作为对象)
documentPrinted=True
端接头
末级
当我第一次单击button1时,所有事情都会按预期进行(打印开始),但当我单击button1进行多次打印时(而不是打印),我会收到错误消息:

my.exe中首次出现“System.Runtime.InteropServices.COMException”类型的异常
正在尝试撤消尚未注册的删除目标(HRESULT中的异常:0x80040100(DRAGDROP_E_NOTREGISTERED))


是什么原因导致此错误?我如何才能消除此错误,以便能够使用所述组件多次打印文档?

在再次调用
导航之前,您似乎忘记将
文档加载
文档打印
设置回
false
。从最后一次打印输出开始,它们仍然是
true
,并且循环中的等待事件逻辑不起作用。也就是说,它应该是:

documentLoaded = False
documentPrinted = False
ie.Navigate(htmlfilename)
While Not documentLoaded AndAlso ie.QueryStatusWB(OLECMDID.OLECMDID_PRINT) <> OLECMDF.OLECMDF_ENABLED
    Application.DoEvents()
    Threading.Thread.Sleep(100)
End While
documentload=False
documentPrinted=False
ie.Navigate(htmlfilename)
在未加载文档且启用ie.QueryStatusWB(OLECMDID.OLECMDID_打印)OLECMDF.OLECMDF_时
Application.DoEvents()
线程。线程。睡眠(100)
结束时

还有一个问题。显然,您不会重复使用
PrintHTMLDocument
中的
InternetExplorer
对象,并在每次打印时创建一个新实例。如果出于某种原因您不想重复使用它,您至少应该在
PrintHTMLDocument
的末尾调用
ie.Quit
。否则,您将依赖.NET垃圾收集器来释放该对象(这是一个进程外COM自动化对象,每个对象都占用一些重要的系统资源)。如果确实要重新使用它,请确保只添加一次事件处理程序。

在再次调用
导航之前,您似乎忘记将
documentLoaded
documentPrinted
设置回
false
。从最后一次打印输出开始,它们仍然是
true
,并且循环中的等待事件逻辑不起作用。也就是说,它应该是:

documentLoaded = False
documentPrinted = False
ie.Navigate(htmlfilename)
While Not documentLoaded AndAlso ie.QueryStatusWB(OLECMDID.OLECMDID_PRINT) <> OLECMDF.OLECMDF_ENABLED
    Application.DoEvents()
    Threading.Thread.Sleep(100)
End While
documentload=False
documentPrinted=False
ie.Navigate(htmlfilename)
在未加载文档且启用ie.QueryStatusWB(OLECMDID.OLECMDID_打印)OLECMDF.OLECMDF_时
Application.DoEvents()
线程。线程。睡眠(100)
结束时

还有一个问题。显然,您不会重复使用
PrintHTMLDocument
中的
InternetExplorer
对象,并在每次打印时创建一个新实例。如果出于某种原因您不想重复使用它,您至少应该在
PrintHTMLDocument
的末尾调用
ie.Quit
。否则,您将依赖.NET垃圾收集器来释放该对象(这是一个进程外COM自动化对象,每个对象都占用一些重要的系统资源)。如果确实要重新使用它,请确保只添加一次事件处理程序。

是的,就是这样!谢谢你。我的代码现在完全按照预期工作。我必须使用新实例来打印文档,但我不知道为什么我的部分代码丢失了?也许我发的“太快了”。是的,每次打印后,我删除处理程序,调用ie.Quit并设置ie=Nothing。我叮叮当当,这足以清洁一个物体。没问题,很高兴它起了作用。如果你做那样的清理你会没事的。是的,就是这样!谢谢你。我的代码现在完全按照预期工作。我必须使用新实例来打印文档,但我不知道为什么我的部分代码丢失了?也许我发的“太快了”。是的,每次打印后,我删除处理程序,调用ie.Quit并设置ie=Nothing。我叮叮当当,这足以清洁一个物体。没问题,很高兴它起了作用。如果你做那样的清理,你会没事的。