【问题标题】:Close a MSI file handle after being downloaded from a website从网站下载后关闭 MSI 文件句柄
【发布时间】:2021-07-27 07:00:23
【问题描述】:

我有一个用于 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() 中的文件时收到以下错误:

进程无法访问文件 %temp%\ol.msi,因为它正被另一个进程使用

如果我使用 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

我想知道如何关闭句柄以避免此错误?非常感谢任何帮助

【问题讨论】:

    标签: vb.net vsto ioexception


    【解决方案1】:

    所以这是我关闭手柄所要做的。打开 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
    

    【讨论】:

      猜你喜欢
      • 2015-09-28
      • 1970-01-01
      • 1970-01-01
      • 2010-10-06
      • 2016-05-13
      • 2016-07-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多