我有一个简单的VB.Net 4 WinForms应用程序,做基本的代码生成。代码生成完美地创建了一个DLL程序集,但每次生成DLL时都需要用GAC以编程方式注册。它必须注册的原因是它是一个COM对象,在部署时通过VB6应用程序通过CreateObject调用。 Eww,我知道。注册生成的DLL VB.Net编程装配不锁定DLL
所有这一切工作正常:该DLL的生成,编程注册和使用从VB6应用程序生成的DLL。
的问题是,我的应用程序,做DLL是没有办法解开它不停止EXE并重新开始它锁定在处理之前的代码生成可以一次生成的DLL。这显然会阻止代码生成工具的用户在不重新启动应用程序的情况下进行更改并重新编译该DLL。
引起锁的代码以下(上线定义变量“ASM”):
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
我试图投掷组件定义到不同的应用程序域如我在见过网络上的一些文章,但我没有提到的实现工作。事实上,几乎所有的程序都以AppDomain的BOTH定义生成的程序集结束。我也试过做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
你挖了一个很深的洞。摆脱所有这一切。然后Project + Properties,Compile选项卡。勾选“注册COM互操作”复选框。 –
@HansPassant我认为他是在运行时动态生成程序集,因此没有项目可以设置该选项。作为替代方案,他可以执行该复选框所执行的操作,即使用RegAsm。 – tcarvin