我有一個簡單的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