从网站下载后关闭 MSI 文件句柄
Close a MSI file handle after being downloaded from a website
我有一个用于 outlook 的 vsto 插件。有一个代码,我可以从网站下载 MSI 文件:
Public Sub DownloadMsiFile()
Try
Dim url As String = "https://www.website.com/ol.msi"
Dim wc As New WebClient()
wc.Headers.Add(HttpRequestHeader.UserAgent, "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; .NET CLR 1.0.3705;")
If File.Exists(My.Computer.FileSystem.SpecialDirectories.Temp & "\ol.msi") Then
System.IO.File.Delete(My.Computer.FileSystem.SpecialDirectories.Temp & "\ol.msi")
End If
wc.DownloadFile(url, My.Computer.FileSystem.SpecialDirectories.Temp & "\ol.msi")
wc.Dispose()
Catch ex As Exception
MessageBox.Show("File couldn't be downloaded: " & ex.Message)
End Try
End Sub
然后我使用以下函数获取 MSI 版本:
Function GetMsiVersion() As String
Try
Dim oInstaller As WindowsInstaller.Installer
Dim oDb As WindowsInstaller.Database
Dim oView As WindowsInstaller.View
Dim oRecord As WindowsInstaller.Record
Dim sSQL As String
oInstaller = CType(CreateObject("WindowsInstaller.Installer"), WindowsInstaller.Installer)
DownloadMsiFile()
If File.Exists(My.Computer.FileSystem.SpecialDirectories.Temp & "\ol.msi") Then
oDb = oInstaller.OpenDatabase(My.Computer.FileSystem.SpecialDirectories.Temp & "\ol.msi", 0)
sSQL = "SELECT `Value` FROM `Property` WHERE `Property`='ProductVersion'"
oView = oDb.OpenView(sSQL)
oView.Execute()
oRecord = oView.Fetch
Return oRecord.StringData(1).ToString()
Else
Return Nothing
End If
Catch ex As Exception
MessageBox.Show("File couldn't be accessed: " & ex.Message)
End Try
End Function
然后我和当前的dll版本做比较,看是否需要下载更新的版本:
Public Sub CheckOLUpdates()
Dim remoteVersion As String = GetMsiVersion()
Dim installedVersion As String = Assembly.GetExecutingAssembly().GetName().Version.ToString
If Not String.IsNullOrEmpty(remoteVersion) Then
Try
If String.Compare(installedVersion, remoteVersion) < 0 Then
Dim Result As DialogResult = MessageBox.Show("A newer version is available for download, do you want to download it now?", "OL", System.Windows.Forms.MessageBoxButtons.OKCancel, MessageBoxIcon.Question)
If Result = 1 Then
System.Diagnostics.Process.Start("http://www.website.com/update")
Else
Exit Sub
End If
Else
MessageBox.Show("You have the latest version installed!", "OL", MessageBoxButtons.OK, MessageBoxIcon.Information)
End If
Catch ex As Exception
End Try
End If
End Sub
如果这个 运行 一次,效果很好。但是,如果我再次尝试检查更新,我会在尝试删除 DownloadMsiFile() 中的文件时收到以下错误:
The process cannot access the file %temp%\ol.msi because it is being used by another process
如果我使用 sysinternals handle.exe 实用程序检查此文件的句柄,我会得到 outlook 进程在此文件上有一个句柄锁:
handle.exe %temp%\ol.msi
Nthandle v4.30 - Handle viewer
Copyright (C) 1997-2021 Mark Russinovich
Sysinternals - www.sysinternals.com
OUTLOOK.EXE pid: 25964 type: File 4FC8: %temp%\ol.msi
我想知道如何关闭句柄以避免出现此错误?非常感谢任何帮助
所以这是关闭句柄我必须做的。我在打开 MSI 文件后添加了以下行:
Marshal.FinalReleaseComObject(oRecord)
oView.Close()
Marshal.FinalReleaseComObject(oView)
Marshal.FinalReleaseComObject(oDb)
oRecord = Nothing
oView = Nothing
oDb = Nothing
所以我的最终代码如下所示:
Function GetMsiVersion() As String
Try
Dim oInstaller As WindowsInstaller.Installer
Dim oDb As WindowsInstaller.Database
Dim oView As WindowsInstaller.View
Dim oRecord As WindowsInstaller.Record
Dim sSQL As String
Dim Version As String
oInstaller = CType(CreateObject("WindowsInstaller.Installer"), WindowsInstaller.Installer)
DownloadMsiFile()
If File.Exists(My.Computer.FileSystem.SpecialDirectories.Temp & "\ol.msi") Then
oDb = oInstaller.OpenDatabase(My.Computer.FileSystem.SpecialDirectories.Temp & "\ol.msi", 0)
sSQL = "SELECT `Value` FROM `Property` WHERE `Property`='ProductVersion'"
oView = oDb.OpenView(sSQL)
oView.Execute()
oRecord = oView.Fetch
Version = oRecord.StringData(1).ToString()
Marshal.FinalReleaseComObject(oRecord)
oView.Close()
Marshal.FinalReleaseComObject(oView)
Marshal.FinalReleaseComObject(oDb)
oRecord = Nothing
oView = Nothing
oDb = Nothing
Else
Version = Nothing
End If
Return Version
Catch ex As Exception
MessageBox.Show("File couldn't be accessed: " & ex.Message)
End Try
End Function
我有一个用于 outlook 的 vsto 插件。有一个代码,我可以从网站下载 MSI 文件:
Public Sub DownloadMsiFile()
Try
Dim url As String = "https://www.website.com/ol.msi"
Dim wc As New WebClient()
wc.Headers.Add(HttpRequestHeader.UserAgent, "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; .NET CLR 1.0.3705;")
If File.Exists(My.Computer.FileSystem.SpecialDirectories.Temp & "\ol.msi") Then
System.IO.File.Delete(My.Computer.FileSystem.SpecialDirectories.Temp & "\ol.msi")
End If
wc.DownloadFile(url, My.Computer.FileSystem.SpecialDirectories.Temp & "\ol.msi")
wc.Dispose()
Catch ex As Exception
MessageBox.Show("File couldn't be downloaded: " & ex.Message)
End Try
End Sub
然后我使用以下函数获取 MSI 版本:
Function GetMsiVersion() As String
Try
Dim oInstaller As WindowsInstaller.Installer
Dim oDb As WindowsInstaller.Database
Dim oView As WindowsInstaller.View
Dim oRecord As WindowsInstaller.Record
Dim sSQL As String
oInstaller = CType(CreateObject("WindowsInstaller.Installer"), WindowsInstaller.Installer)
DownloadMsiFile()
If File.Exists(My.Computer.FileSystem.SpecialDirectories.Temp & "\ol.msi") Then
oDb = oInstaller.OpenDatabase(My.Computer.FileSystem.SpecialDirectories.Temp & "\ol.msi", 0)
sSQL = "SELECT `Value` FROM `Property` WHERE `Property`='ProductVersion'"
oView = oDb.OpenView(sSQL)
oView.Execute()
oRecord = oView.Fetch
Return oRecord.StringData(1).ToString()
Else
Return Nothing
End If
Catch ex As Exception
MessageBox.Show("File couldn't be accessed: " & ex.Message)
End Try
End Function
然后我和当前的dll版本做比较,看是否需要下载更新的版本:
Public Sub CheckOLUpdates()
Dim remoteVersion As String = GetMsiVersion()
Dim installedVersion As String = Assembly.GetExecutingAssembly().GetName().Version.ToString
If Not String.IsNullOrEmpty(remoteVersion) Then
Try
If String.Compare(installedVersion, remoteVersion) < 0 Then
Dim Result As DialogResult = MessageBox.Show("A newer version is available for download, do you want to download it now?", "OL", System.Windows.Forms.MessageBoxButtons.OKCancel, MessageBoxIcon.Question)
If Result = 1 Then
System.Diagnostics.Process.Start("http://www.website.com/update")
Else
Exit Sub
End If
Else
MessageBox.Show("You have the latest version installed!", "OL", MessageBoxButtons.OK, MessageBoxIcon.Information)
End If
Catch ex As Exception
End Try
End If
End Sub
如果这个 运行 一次,效果很好。但是,如果我再次尝试检查更新,我会在尝试删除 DownloadMsiFile() 中的文件时收到以下错误:
The process cannot access the file %temp%\ol.msi because it is being used by another process
如果我使用 sysinternals handle.exe 实用程序检查此文件的句柄,我会得到 outlook 进程在此文件上有一个句柄锁:
handle.exe %temp%\ol.msi
Nthandle v4.30 - Handle viewer
Copyright (C) 1997-2021 Mark Russinovich
Sysinternals - www.sysinternals.com
OUTLOOK.EXE pid: 25964 type: File 4FC8: %temp%\ol.msi
我想知道如何关闭句柄以避免出现此错误?非常感谢任何帮助
所以这是关闭句柄我必须做的。我在打开 MSI 文件后添加了以下行:
Marshal.FinalReleaseComObject(oRecord)
oView.Close()
Marshal.FinalReleaseComObject(oView)
Marshal.FinalReleaseComObject(oDb)
oRecord = Nothing
oView = Nothing
oDb = Nothing
所以我的最终代码如下所示:
Function GetMsiVersion() As String
Try
Dim oInstaller As WindowsInstaller.Installer
Dim oDb As WindowsInstaller.Database
Dim oView As WindowsInstaller.View
Dim oRecord As WindowsInstaller.Record
Dim sSQL As String
Dim Version As String
oInstaller = CType(CreateObject("WindowsInstaller.Installer"), WindowsInstaller.Installer)
DownloadMsiFile()
If File.Exists(My.Computer.FileSystem.SpecialDirectories.Temp & "\ol.msi") Then
oDb = oInstaller.OpenDatabase(My.Computer.FileSystem.SpecialDirectories.Temp & "\ol.msi", 0)
sSQL = "SELECT `Value` FROM `Property` WHERE `Property`='ProductVersion'"
oView = oDb.OpenView(sSQL)
oView.Execute()
oRecord = oView.Fetch
Version = oRecord.StringData(1).ToString()
Marshal.FinalReleaseComObject(oRecord)
oView.Close()
Marshal.FinalReleaseComObject(oView)
Marshal.FinalReleaseComObject(oDb)
oRecord = Nothing
oView = Nothing
oDb = Nothing
Else
Version = Nothing
End If
Return Version
Catch ex As Exception
MessageBox.Show("File couldn't be accessed: " & ex.Message)
End Try
End Function