以编程方式注册生成的VB.Net DLL程序集而不锁定DLL
我有一个简单的VB.NET4 WinForms应用程序,可以生成基本代码。代码生成可以创建一个DLL程序集,但是每次生成DLL时都需要以编程方式向GAC注册。必须注册它的原因是,它是一个COM对象,部署时通过VB6应用程序的CreateObject调用它。哦,我知道 所有这些工作都很好:DLL生成、以编程方式注册以及使用VB6应用程序生成的DLL 问题是,在进程锁定DLL之前,执行代码生成的应用程序只能生成DLL一次,如果不停止EXE并再次启动它,则无法解锁DLL。这显然会阻止代码生成工具的用户在不重新启动应用程序的情况下进行更改和重新编译DLL 导致锁定的代码如下(在定义变量“asm”的行上): 正如我在web上的许多文章中看到的那样,我已经尝试将程序集定义放到不同的AppDomain中,但是我提出的实现都没有成功。事实上,几乎所有的应用程序都以生成的程序集结束,然后在两个AppDomain中定义。我也尝试过只加载ReflectionOnly程序集,但为了实现寄存器功能,必须在活动模式而不是反射模式下加载程序集 它抛出的实际错误是这个奇妙的宝石:以编程方式注册生成的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。这显然会阻止代码生成工具的用户
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