Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/vb.net/15.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
以编程方式注册生成的VB.Net DLL程序集而不锁定DLL_.net_Vb.net_Process_Locking_Regasm - Fatal编程技术网

以编程方式注册生成的VB.Net DLL程序集而不锁定DLL

以编程方式注册生成的VB.Net DLL程序集而不锁定DLL,.net,vb.net,process,locking,regasm,.net,Vb.net,Process,Locking,Regasm,我有一个简单的VB.NET4 WinForms应用程序,可以生成基本代码。代码生成可以创建一个DLL程序集,但是每次生成DLL时都需要以编程方式向GAC注册。必须注册它的原因是,它是一个COM对象,部署时通过VB6应用程序的CreateObject调用它。哦,我知道 所有这些工作都很好:DLL生成、以编程方式注册以及使用VB6应用程序生成的DLL 问题是,在进程锁定DLL之前,执行代码生成的应用程序只能生成DLL一次,如果不停止EXE并再次启动它,则无法解锁DLL。这显然会阻止代码生成工具的用户

我有一个简单的VB.NET4 WinForms应用程序,可以生成基本代码。代码生成可以创建一个DLL程序集,但是每次生成DLL时都需要以编程方式向GAC注册。必须注册它的原因是,它是一个COM对象,部署时通过VB6应用程序的CreateObject调用它。哦,我知道

所有这些工作都很好:DLL生成、以编程方式注册以及使用VB6应用程序生成的DLL

问题是,在进程锁定DLL之前,执行代码生成的应用程序只能生成DLL一次,如果不停止EXE并再次启动它,则无法解锁DLL。这显然会阻止代码生成工具的用户在不重新启动应用程序的情况下进行更改和重新编译DLL

导致锁定的代码如下(在定义变量“asm”的行上):

正如我在web上的许多文章中看到的那样,我已经尝试将程序集定义放到不同的AppDomain中,但是我提出的实现都没有成功。事实上,几乎所有的应用程序都以生成的程序集结束,然后在两个AppDomain中定义。我也尝试过只加载ReflectionOnly程序集,但为了实现寄存器功能,必须在活动模式而不是反射模式下加载程序集

它抛出的实际错误是这个奇妙的宝石:

Error Number: BC31019
Error Message: Unable to write to output file 'C:\Users\Me\AppData\Local\Temp\my.dll': The process cannot access the file because it is being used by another process. 
如果有人能告诉我我能做些什么来解决这个问题,我将不胜感激!正如我所说,它在第一次编译DLL时工作得很好,但是DLL的后续编译失败,因为程序集被应用程序进程锁定

下面是我完整的编译器类定义。我还留了一些我试过的东西,抱歉弄得乱七八糟:

Imports System.CodeDom.Compiler
Imports System.Text
Imports System.IO
Imports System.Reflection
Imports System.Runtime.InteropServices

Public Class ExitCompiler

Private _errorMessageContents As String = ""
Private _errorCount As Integer = -1

Public ReadOnly Property ErrorMessageText As String
    Get
        Return _errorMessageContents
    End Get
End Property

Public ReadOnly Property ErrorCount As Integer
    Get
        Return _errorCount
    End Get
End Property

Public Function Compile(ByVal codeFileInfo As FileInfo) As Boolean
    Dim success As Boolean = False
    Dim codeContents As String = CodeReader.ReadAllContents(codeFileInfo.FullName)

    success = Compile(codeContents)

    Return success
End Function

Public Function Compile(ByVal codeContents As String) As Boolean
    _errorMessageContents = ""

    'asmAppDomain = AppDomain.CreateDomain("asmAppDomain", AppDomain.CurrentDomain.Evidence, AppDomain.CurrentDomain.BaseDirectory, AppDomain.CurrentDomain.RelativeSearchPath, AppDomain.CurrentDomain.ShadowCopyFiles)

    LogLoadedAssemblies(AppDomain.CurrentDomain)
    ' LogLoadedAssemblies(asmAppDomain)

    Try
        ' Remove output assemblies from previous compilations
        'RemoveAssembly()
    Catch uaEx As UnauthorizedAccessException
        Throw uaEx
    End Try

    Dim success As Boolean = False
    Dim outputFileName As String = Path.Combine(My.Computer.FileSystem.SpecialDirectories.Temp, "my.dll")
    Dim results As CompilerResults

    Dim codeProvider As New VBCodeProvider()
    Dim parameters As New CompilerParameters()

    parameters.TreatWarningsAsErrors = False
    parameters.CompilerOptions = "/optimize"
    parameters.TempFiles = New TempFileCollection(My.Computer.FileSystem.SpecialDirectories.Temp, False)
    parameters.OutputAssembly = outputFileName
    parameters.ReferencedAssemblies.Add("System.dll")
    parameters.ReferencedAssemblies.Add("System.Data.dll")
    parameters.ReferencedAssemblies.Add("System.Xml.dll")

    results = codeProvider.CompileAssemblyFromSource(parameters, codeContents)

    _errorCount = results.Errors.Count

    If _errorCount > 0 Then
        success = False

        'There were compiler errors
        Dim sb As New StringBuilder
        For Each compileError As CompilerError In results.Errors
            sb.AppendLine()
            sb.AppendLine("Line number: " & compileError.Line)
            sb.AppendLine("Error Number: " & compileError.ErrorNumber)
            sb.AppendLine("Error Message: " & compileError.ErrorText)
            sb.AppendLine()
        Next

        _errorMessageContents = sb.ToString()
    Else
        success = True

        ' Successful compile, now generate the TLB (Optional)
        'success = GenerateTypeLib()

        If success Then
            ' Type lib generated, now register with GAC
            Try
                success = RegisterAssembly()
            Catch ex As Exception
                success = False
            End Try
        End If
    End If

    Return success
End Function

'Private Function GenerateTypeLib() As Boolean
'    Dim success As Boolean = False

'    Try
'        Dim asm As [Assembly] = [Assembly].ReflectionOnlyLoadFrom(My.Computer.FileSystem.SpecialDirectories.Temp & "\my.dll")
'        Dim converter As New TypeLibConverter()
'        Dim eventHandler As New ConversionEventHandler()

'        Dim typeLib As UCOMICreateITypeLib = CType(converter.ConvertAssemblyToTypeLib(asm, My.Computer.FileSystem.SpecialDirectories.Temp & "\my.tlb", 0, eventHandler), UCOMICreateITypeLib)
'        typeLib.SaveAllChanges()

'        success = True
'    Catch ex As Exception
'        success = False
'        Throw ex
'    End Try

'    Return success
'End Function

Public Function RegisterAssembly() As Boolean
    Dim success As Boolean = False

    Try
        Dim asm As [Assembly] = [Assembly].LoadFile(Path.Combine(My.Computer.FileSystem.SpecialDirectories.Temp, "my.dll"))
        Dim regasm As New RegistrationServices()

        success = regasm.RegisterAssembly(asm, AssemblyRegistrationFlags.None)
    Catch ex As Exception
        success = False
        Throw ex
    End Try

    Return success
End Function

Public Sub RemoveAssembly()
    'AppDomain.Unload(asmAppDomain)

    File.Delete(Path.Combine(My.Computer.FileSystem.SpecialDirectories.Temp, "my.dll"))
    'File.Delete(Path.Combine(My.Computer.FileSystem.SpecialDirectories.Temp, "my.tlb"))
End Sub

Private Shared Sub LogLoadedAssemblies(appDomain__1 As AppDomain)
    Dim sb As New StringBuilder

    sb.AppendLine("Loaded assemblies in appdomain: " & appDomain__1.FriendlyName)
    For Each loadedAssembly As Assembly In AppDomain.CurrentDomain.GetAssemblies()
        sb.AppendLine("- " & loadedAssembly.GetName().Name)
    Next

    MessageBox.Show(sb.ToString())
End Sub

'Private Shared Function CurrentDomain_ReflectionOnlyAssemblyResolve(sender As Object, args As ResolveEventArgs) As Assembly
'    Return System.Reflection.Assembly.ReflectionOnlyLoad(args.Name)
'End Function
End Class

在自动安装.Net安装程序类时,我们处理此问题的方法是在新的appdomain中执行注册,这与在当前appdomain中加载和锁定DLL有相同的问题

在我到达之前,您可能会考虑使用一个额外的快捷方式调用一个进程调用ReGVR32来悄悄地登记到DLL。 以下代码特定于我们的解决方案,但应该能让您有所了解:

''' <summary>
''' Register the specified file, using the mechanism specified in the .Registration property
''' </summary>
''' <param name="sFileName"></param>
''' <remarks></remarks>
Private Sub Register(ByVal sFileName As String)
    ' Exceptions are ignored

    Dim oDomain As AppDomain = Nothing
    Try
        Dim oSetup As New System.AppDomainSetup()

        With oSetup
            .ApplicationBase = ApplicationConfiguration.AppRoot
            .ConfigurationFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile
            .LoaderOptimization = LoaderOptimization.SingleDomain
            .DisallowBindingRedirects = False
            .DisallowCodeDownload = True
        End With

        ' Launch the application
        oDomain = AppDomain.CreateDomain("AutoUpdater", AppDomain.CurrentDomain.Evidence, oSetup)

        oDomain.CreateInstance(GetType(FileRegistration).Assembly.FullName, GetType(FileRegistration).ToString, True, Reflection.BindingFlags.Default, Nothing, New Object() {sFileName}, Nothing, Nothing, AppDomain.CurrentDomain.Evidence)
    Catch theException As Exception
        ' Suppress errors to the end user
        Call ReportError(theException, True)
    Finally
        If oDomain IsNot Nothing Then
            AppDomain.Unload(oDomain)
        End If
    End Try
End Sub
“”
''使用.Registration属性中指定的机制注册指定的文件
''' 
''' 
''' 
专用子寄存器(ByVal sFileName作为字符串)
“例外情况被忽略
作为AppDomain的Dim oDomain=无
尝试
Dim oSetup作为新系统。AppDomainSetup()
使用oSetup
.ApplicationBase=ApplicationConfiguration.AppRoot
.ConfigurationFile=AppDomain.CurrentDomain.SetupInformation.ConfigurationFile
.LoaderOptimization=LoaderOptimization.SingleDomain
.DisallowBindingRedirects=False
.DisallowCodeDownload=True
以
“启动应用程序
oDomain=AppDomain.CreateDomain(“自动更新程序”,AppDomain.CurrentDomain.Evidence,oSetup)
oDomain.CreateInstance(GetType(FileRegistration).Assembly.FullName,GetType(FileRegistration).ToString,True,Reflection.BindingFlags.Default,Nothing,New Object(){sFileName},Nothing,Nothing,AppDomain.CurrentDomain.Evidence)
将异常捕获为异常
'禁止向最终用户发送错误
调用报告错误(异常,真)
最后
如果oDomain不是什么,那么
AppDomain.Unload(oDomain)
如果结束
结束尝试
端接头
类别文件注册:

''' <summary>
''' This class is used to register .Net installer files. This functionality is contained in its own class because it is 
''' launched in a separate appdomain in order to prevent loading the files into the host appdomain (which locks 
''' them and makes them unavailable until the host application is shutdown).
''' </summary>
''' <remarks></remarks>
Public Class FileRegistration
    Inherits MarshalByRefObject

    Public Sub New(ByVal sFileName As String)
        ' Exceptions are ignored
        Try
            Using oInstaller As New System.Configuration.Install.AssemblyInstaller(sFileName, New String() {"/logfile=autoupdate.log"})
                Dim htSavedState As New Collections.Hashtable()

                oInstaller.Install(htSavedState)
                oInstaller.Commit(htSavedState)
            End Using
        Catch theException As Exception
            ' Suppress errors to the end user
            Call ReportError(theException, True)
        End Try
    End Sub
“”
''此类用于注册.Net安装程序文件。此功能包含在它自己的类中,因为它是
''在单独的appdomain中启动,以防止将文件加载到主机appdomain(锁定
''并使其在主机应用程序关闭之前不可用)。
''' 
''' 
公共类文件注册
继承MarshalByRefObject
Public Sub New(ByVal sFileName作为字符串)
“例外情况被忽略
尝试
将oInstaller用作新的System.Configuration.Install.AssemblyInstaller(sFileName,新字符串(){“/logfile=autoupdate.log”})
Dim htSavedState作为新集合。哈希表()
oInstaller.Install(htSavedState)
oInstaller.Commit(htSavedState)
终端使用
将异常捕获为异常
'禁止向最终用户发送错误
调用报告错误(异常,真)
结束尝试
端接头

我们处理自动安装.Net安装程序类的方法是在新的appdomain中执行注册,该类在当前appdomain中加载和锁定DLL时存在相同的问题

在我到达之前,您可能会考虑使用一个额外的快捷方式调用一个进程调用ReGVR32来悄悄地登记到DLL。 以下代码特定于我们的解决方案,但应该能让您有所了解:

''' <summary>
''' Register the specified file, using the mechanism specified in the .Registration property
''' </summary>
''' <param name="sFileName"></param>
''' <remarks></remarks>
Private Sub Register(ByVal sFileName As String)
    ' Exceptions are ignored

    Dim oDomain As AppDomain = Nothing
    Try
        Dim oSetup As New System.AppDomainSetup()

        With oSetup
            .ApplicationBase = ApplicationConfiguration.AppRoot
            .ConfigurationFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile
            .LoaderOptimization = LoaderOptimization.SingleDomain
            .DisallowBindingRedirects = False
            .DisallowCodeDownload = True
        End With

        ' Launch the application
        oDomain = AppDomain.CreateDomain("AutoUpdater", AppDomain.CurrentDomain.Evidence, oSetup)

        oDomain.CreateInstance(GetType(FileRegistration).Assembly.FullName, GetType(FileRegistration).ToString, True, Reflection.BindingFlags.Default, Nothing, New Object() {sFileName}, Nothing, Nothing, AppDomain.CurrentDomain.Evidence)
    Catch theException As Exception
        ' Suppress errors to the end user
        Call ReportError(theException, True)
    Finally
        If oDomain IsNot Nothing Then
            AppDomain.Unload(oDomain)
        End If
    End Try
End Sub
“”
''使用.Registration属性中指定的机制注册指定的文件
''' 
''' 
''' 
专用子寄存器(ByVal sFileName作为字符串)
“例外情况被忽略
作为AppDomain的Dim oDomain=无
尝试
Dim oSetup作为新系统。AppDomainSetup()
使用oSetup
.ApplicationBase=ApplicationConfiguration.AppRoot
.ConfigurationFile=AppDomain.CurrentDomain.SetupInformation.ConfigurationFile
.LoaderOptimization=LoaderOptimization.SingleDomain
.DisallowBindingRedirects=False
.DisallowCodeDownload=True
以
“启动应用程序
oDomain=AppDomain.CreateDomain(“自动更新程序”,AppDomain.CurrentDomain.Evidence,oSetup)
CreateInstance(GetType(FileRegistration).Assembly.FullName,G