使用《VB.net webbrowser 如何实现自定义下载 IDownloadManager》中的控件ExtendedWebBrowser(下载控件),并扩展了NewWindow2。
使用ExtendedWebBrowser_1过程中,遇到很多问题,花了几天时间,终于解决了所有问题。
问题1:接管了下载后,发现大文件下载,主程序会阻塞。
一开始,以为是在写文件时因为IO响应导致阻塞,改用异步写,等等...尝试,发现阻塞依然,看过《C# 用FileStream.WriteAsync 异步读文件,调用线程还是被阻塞了》等文章后,问题依然未能解决。
最后尝试主程序不写文件(就是接管下载后,在OnDataAvailable中对接收数据不操作),不做任何操作,阻塞依然存在。阻塞会导致下载中断,而且这种情况与下载文件大小无关,即使很小几M的文件也会发生。
苦思中,记起以前写一个延时函数时,为了不阻塞而加入了Application.DoEvents()语句,于是在最频繁操作的OnDataAvailable中加入Application.DoEvents()语句,问题终于得到完满解决。
问题2:写文件
一开始,是主程序写文件,遇到太多麻烦,在解决问题1中,发现接管了下载后,其实IE是有在后台进程中将文件下载到IE缓冲区的,OnProgress第一次便是返回IE缓冲区中下载的文件名,于是便改用:等下载完后从IE缓冲区复制文件。(貌似IE原有下载器也是这样干的?)
问题3:对于会弹出新窗口的下载,在进行第二次下载时,没有触发下载。
因为主程序中接管弹出窗口的Extendedwebbrowser_2一直没关闭(IE中下载窗口是立即关闭的),并且发现,在NewWindow2中将弹出下载转到Extendedwebbrowser_2触发下载时,Extendedwebbrowser_2并没有触发DocumentCompleted,估计就是这里导致第二次下载时不能触发。
解决办法:在下载完后,Extendedwebbrowser_2加载空白页"about:blank",问题解决。
下面是IWebBrowserDownloadManager接口完整代码:
Imports Remotion.Dms.Clients.Windows.WebBrowserControl
Imports System.IO
Namespace MyDownloadmanager '定义接口,以实现接口引用 2023.10.27
Public Class MyDownloadmanager
Implements IWebBrowserDownloadManager
Dim INetCacheFile As String
'一些状态的判定(True、False),其中的一种状态(True或False)必须放在接口内进行设定,
'不能全部都靠通过外部进程来设定,外部进程只进行其中一种状态的改变就好,否则因为轮询时间差而导致不同步引发非预期结果发生。
'例如:AfterLoadBlank
#Region "增加属性,将接口的数据传递出去以及传进来"
#Region "可读写属性"
Private _ContinueDownload As Boolean = True
Public Property ContinueDownload() As Boolean
Get
Return _ContinueDownload
End Get
Set(ByVal value As Boolean)
_ContinueDownload = value
End Set
End Property
Private _DownloadDir As String = ""
Public Property DownloadDir() As String
Get
Return _DownloadDir
End Get
Set(ByVal value As String)
_DownloadDir = value
End Set
End Property
Private _AttchmentFilename As String = ""
Public Property AttchmentFilename() As String
Get
Return _AttchmentFilename
End Get
Set(ByVal value As String)
_AttchmentFilename = value
End Set
End Property
'对于会弹出新窗口的下载,因为程序中接管的webbrowser一直没关闭,
’在下载完后,需要加载一次新页(在这里加载空白页"about:blank"),
‘否则可能无法进行下一次下载。
Private _AfterLoadBlank As Boolean = False
Public Property AfterLoadBlank() As Boolean
Get
Return _AfterLoadBlank
End Get
Set(ByVal value As Boolean)
_AfterLoadBlank = value
End Set
End Property
#End Region
#Region "ReadOnly Property"
Dim _DownloadFileName As String = ""
Public ReadOnly Property DownloadFileName() As String
Get
Return _DownloadFileName
End Get
End Property
Private _totalSize As Integer
Public ReadOnly Property GetTotalSize() As Integer
Get
Return _totalSize
End Get
End Property
Private _currentValue As Integer
Public ReadOnly Property GetCurrentValue() As Integer
Get
Return _currentValue
End Get
End Property
Private _success As Boolean
Public ReadOnly Property GetSuccess() As Boolean
Get
Return _success
End Get
End Property
Private _statusText As String
Public ReadOnly Property GetStatusText() As String
Get
Return _statusText
End Get
End Property
Private _isAborted As Boolean
Public ReadOnly Property GetisAborted() As Boolean
Get
Return _isAborted
End Get
End Property
Private _IsDownloadCompleted As Boolean = False
'下载开始时,设置为false,下载结束或退出时,设置为True
Public ReadOnly Property IsDownloadCompleted() As Boolean
Get
Return _IsDownloadCompleted
End Get
End Property
Private _OnStartDownloading As Boolean = False
'下载开始时,设置为false,下载结束或退出时,设置为True
Public ReadOnly Property OnStartDownloading() As Boolean
Get
Return _OnStartDownloading
End Get
End Property
#End Region
#End Region
#Region "接口函数"
Public Sub OnAborted() Implements Remotion.Dms.Clients.Windows.WebBrowserControl.IWebBrowserDownloadManager.OnAborted
WriteRunLog("OnAborted")
_isAborted = True
_IsDownloadCompleted = True
_OnStartDownloading = False
End Sub
Public Function OnDataAvailable(ByVal buffer() As Byte, ByVal bytesAvailable As Integer) As Boolean Implements Remotion.Dms.Clients.Windows.WebBrowserControl.IWebBrowserDownloadManager.OnDataAvailable
_currentValue += bytesAvailable
'需要加这行,否则可能下载时发生阻塞,导致下载中断,而且这种情况与下载文件大小无关,即使很小几M的文件也会发生。
Application.DoEvents()
Return _ContinueDownload
End Function
'在下载完后,需要加载一次新页(在这里加载空白页"about:blank"),否则可能无法进行下一次下载。
Public Sub OnDownloadCompleted(ByVal success As Boolean, ByVal statusText As String) Implements Remotion.Dms.Clients.Windows.WebBrowserControl.IWebBrowserDownloadManager.OnDownloadCompleted
_isAborted = False
_IsDownloadCompleted = True
_OnStartDownloading = False
_AfterLoadBlank = True
_success = success
_statusText = statusText
_AttchmentFilename = ""
WriteRunLog("OnDownloadCompleted:" + success.ToString + " " + statusText)
If success Then
If String.IsNullOrEmpty(INetCacheFile) Then
WriteRunLog("没有找到IE缓冲区文件!文件 " + _DownloadFileName + " 下载失败!")
Else
File.Copy(INetCacheFile, _DownloadFileName, overwrite:=True) '从IE缓冲区复制文件
WriteRunLog("找到IE缓冲区文件: " + INetCacheFile + ",复制到:" + _DownloadFileName)
End If
End If
End Sub
Public Function OnProgress(ByVal currentValue As Integer, ByVal totalSize As Integer, ByVal statusText As String) As Boolean Implements Remotion.Dms.Clients.Windows.WebBrowserControl.IWebBrowserDownloadManager.OnProgress
_totalSize = totalSize
'从第一次OnProgress中获取下载文件名
If String.IsNullOrEmpty(_DownloadFileName) Then
_DownloadFileName = MyGetFileName(statusText)
If String.IsNullOrEmpty(_DownloadFileName) Then
_DownloadFileName = "TmpFile"
End If
If Directory.Exists(_DownloadDir) Then
_DownloadFileName = _DownloadDir + "\" + _DownloadFileName
End If
End If
If String.IsNullOrEmpty(INetCacheFile) Then
If InStr(statusText, "Windows\INetCache") > 0 Then '查找IE缓冲区文件 保存路径、文件名
INetCacheFile = statusText
'WriteRunLog("OnProgress找到IE缓冲区文件: " + INetCacheFile)
End If
End If
System.Windows.Forms.Application.DoEvents()
Return _ContinueDownload
End Function
Public Function OnStartDownload(ByVal uri As System.Uri) As Boolean Implements Remotion.Dms.Clients.Windows.WebBrowserControl.IWebBrowserDownloadManager.OnStartDownload
_currentValue = 0
_OnStartDownloading = True
_ContinueDownload = True
_IsDownloadCompleted = False
INetCacheFile = ""
_DownloadFileName = ""
WriteRunLog("OnStartDownload :" + uri.ToString)
Return True
End Function
'OnStartDownload:http://115.1.115.15:9080/FrntMonitor/servlet/com.icbc.cte.cs.servlet.CSReqServlet
'1、第一次获得文件名 OnProgress:0 totalSize:0 statusText: C:\Users\gdzs-liyh\AppData\Local\Microsoft\Windows\Temporary Internet Files\Content.IE5\0F2VEW6C\statatmdev[2].xls
'2、第二次获得下载链接 OnProgress:3483 totalSize:0 statusText:(OnStartDownload中的网址:http://115.1.115.15:9080/FrntMonitor/servlet/com.icbc.cte.cs.servlet.CSReqServlet)
'3483就是在这时候读取的数据大小。
'OnProgress:3483 totalSize:0 statusText: C:\Users\gdzs-liyh\AppData\Local\Microsoft\Windows\Temporary Internet Files\Content.IE5\0F2VEW6C\statatmdev[2].xls
'OnDataAvailable:38281 (这个就是文件的实际大小)(可能文件小,此时文件已经下载到缓存:C:\Users\gdzs-liyh\AppData\Local\Microsoft\Windows\Temporary Internet Files\Content.IE5\0F2VEW6C\statatmdev[2].xls)
'OnProgress:38281 totalSize:0 statusText:(OnStartDownload中的网址)
'OnDownloadCompleted
'=================================
'OnStartDownload :http://115.96.14.11/kjbbs/UpLoadFile/2010-7/20107214401523292.doc
'1、第一次获得文件名 OnProgress:0 totalSize:0 statusText :http://115.96.14.11/kjbbs/UpLoadFile/2010-7/20107214401523292.doc
'2、第二次获得下载链接 OnProgress:119296 totalSize:119296 statusText :http://115.96.14.11/kjbbs/UpLoadFile/2010-7/20107214401523292.doc
'OnProgress:119296 totalSize:119296 statusText :C:\Users\gdzs-liyh\AppData\Local\Microsoft\Windows\Temporary Internet Files\Content.IE5\5Q44G40U\20107214401523292.doc
'OnProgress:119296 totalSize:119296 statusText :http://115.96.14.11/kjbbs/UpLoadFile/2010-7/20107214401523292.doc
'OnDataAvailable:119296 (可能文件小,此时文件已经下载到缓存:C:\Users\gdzs-liyh\AppData\Local\Microsoft\Windows\Temporary Internet Files\Content.IE5\0F2VEW6C\statatmdev[2].xls)
'OnDownloadCompleted
#End Region
Shared Sub WriteRunLog(ByVal MyMsg As String)
'Using w As StreamWriter = File.AppendText("RunLog.txt")
Dim w As StreamWriter
If File.Exists("RunLog.txt") Then
If My.Computer.FileSystem.GetFileInfo("RunLog.txt").Length > 10485760 Then '2017.5.4 文件大于10M,清0
w = File.CreateText("RunLog.txt")
w.Write("文件大于10M,置0从头开始!")
w.Write(Chr(9))
Else
w = File.AppendText("RunLog.txt")
End If
Else
w = File.CreateText("RunLog.txt")
End If
w.Write(Now)
w.Write(Chr(9)) '插入Tab键
w.WriteLine(MyMsg)
w.Flush()
w.Close()
'End Using
End Sub
Public Function MyGetFileName(ByVal inStr As String) As String
'获取文件名, '文件夹名、文件名不能包含下列字符\/:*?"<>|
Dim ss As String
ss = System.IO.Path.GetFileName(inStr)
Dim n = InStrRev(ss, "=")
If n < ss.Length Then
ss = ss.Substring(n)
End If
MyGetFileName = ss.Replace("\", "").Replace("/", "").Replace(":", "").Replace("*", "").Replace("?", "").Replace(Chr(34), "").Replace("<", "").Replace(">", "").Replace("|", "")
If InStrRev(MyGetFileName, "[") > 1 And InStrRev(MyGetFileName, "[") < InStrRev(MyGetFileName, "]") Then '将 21018102002617385797[1] 中的 [1] 去掉
MyGetFileName = Left(MyGetFileName, InStrRev(MyGetFileName, "[") - 1) + Mid(MyGetFileName, InStrRev(MyGetFileName, "]") + 1)
End If
MyGetFileName = _AttchmentFilename + MyGetFileName
End Function
End Class
End Namespace