.net - 在不锁定DLL的情况下以编程方式注册生成的VB.Net DLL程序集

  显示原文与译文双语对照的内容
0 0

我有一个简单的VB.Net 4 WinForms应用程序,它可以。 代码生成完全创建一个DLL程序集,但每次生成DLL时都需要以编程方式注册。 它必须注册的原因是,它是一个from对象,当部署时通过iseries应用程序调用。 嗯我知道。

所有这些工作都很正常: 使用程序生成 DLL,以编程方式从VB6应用程序中使用生成的DLL 。

问题是,代码生成的应用程序只能在进程被锁定之前生成 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中,因为我已经在web上看到了一些实现。 实际上,几乎所有这些都是由生成的程序集结束的,然后在两个应用程序。 我还尝试执行ReflectionOnly程序集负载,但是为了使 register 函数在活动模式不反射模式下加载。

它抛出的实际错误是这个出色的gem:


Error Number: BC31019
Error Message: Unable to write to output file 'C:UsersMeAppDataLocalTempmy.dll': The process cannot access the file because it is being used by another process. 

如果有人对我有什么可以解决这个问题的答案,我会大大感谢 ! 像我说的那样,它工作得很好,但是后面的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

时间: 原作者:

0 0

我们处理这个方法的方法是自动安装. NET 安装程序类,它与在当前appdomain中加载和锁定DLL的问题相同。

然而,在我认为这一点之前,你可以考虑使用一个进程调用to来静默地调用 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

类 FileRegistration:


''' <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

原作者:
0 0

需要以编程方式使用GAC注册。 它必须注册的原因是它是一个com对象

不需要将. NET-based com对象放入GAC中。 只需使用标准的.NET regasm实用程序对它们进行 register,你可以使用 System.Diagnostics.Proces 对象将regasm实用程序作为外部进程调用。

是否有其他原因将GAC用于你的com对象?

原作者:
0 0

当你使用CompileAssemblyFromSource时,你不仅将程序集加载到当前进程中,而是将它的加载到当前的appdomain中。

你是否考虑过使用 命令行 编译器 vbc? 它将独立于应用程序域执行编译,然后只在磁盘上创建 DLL,没有对它的引用将锁定它。

原作者:
...