本文介绍了编程注册生成VB.Net DLL组件没有锁定该DLL的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个简单的VB.Net 4 WinForms应用程序,做基本的code一代。在code一代创建一个DLL组件完全正常,但DLL生成每次它需要编程与GAC注册。它必须被登记的原因是,它是一个COM对象,它当展开时被通过的CreateObject从VB6的应用程序调用。 EWW,我知道了。

所有这一切工作正常:该DLL的生成,注册编程和使用生成的DLL从VB6应用程序

的问题是,我的应用程序,做了code代只能生成DLL一次之前该DLL被锁定由过程没有办法解锁无需停止EXE和再次启动它。这显然​​$ P $作出的改变和重新编译DLL,​​无需重新启动应用程序pvents的code生成工具的用户。

在code,导致锁如下(就行定义的变量汇编):

 公共功能RegisterAssembly()作为布尔
    昏暗的成功作为布尔= FALSE

    尝试
        昏暗的ASM为[assembly] = [大会] .LoadFile(Path.Combine(My.Computer.FileSystem.SpecialDirectories.Temp,my.dll))
        昏暗的regasm作为新RegistrationServices的()

        成功= regasm.RegisterAssembly(ASM,AssemblyRegistrationFlags.None)
    抓住EX为例外
        成功=假
        投掷前
    结束尝试

    返回成功
端功能
 

我已经试过扔组件定义成不同的AppDomain,因为我已经看到了一些在网络上的文章,但没有,我已经拿出实施工作过。事实上,几乎所有的人都结束了与生成的程序集,然后被在这两个应用程序域的定义。我也试着做了ReflectionOnly的组件负载但为了在寄存器功能的组件必须在主动模式下加载不反射模式。

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

 错误编号:BC31019
错误信息:无法写入输出文件C:\用户\我\应用程序数据\本地的\ Temp \ my.dll:该进程无法访问该文件,因为它正由另一个进程使用。
 

如果任何人有什么我可以做些什么来解决这个问题,我的答案,我会大大AP preciative!就像我说的,它的伟大工程的第一个DLL编译,但该DLL随后编译失败,因为该组件是由应用​​程序锁定。

我的完整的编译器类定义如下。我已经留在了一些额外的东西,我试过,遗憾的混乱:

 导入系统。codeDom.Compiler
进口System.Text
进口System.IO
进口的System.Reflection
进口了System.Runtime.InteropServices

公共类ExitCompiler

私人_errorMessageContents作为字符串=
私人_errorCount作为整数= -1

公共只读属性ErrorMessageText作为字符串
    得到
        返回_errorMessageContents
    最终获取
高端物业

公共只读属性的ErrorCount作为整数
    得到
        返回_errorCount
    最终获取
高端物业

公共函数编译(BYVAL codeFileInfo作为的FileInfo)作为布尔
    昏暗的成功作为布尔= FALSE
    昏暗codeContents的String = codeReader.ReadAllContents(codeFileInfo.FullName)

    成功=编译(codeContents)

    返回成功
端功能

公共函数编译(BYVAL codeContents作为字符串)作为布尔
    _errorMessageContents =

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

    LogLoadedAssemblies(AppDomain.CurrentDomain)
    LogLoadedAssemblies(asmAppDomain)

    尝试
        从previous汇编删除输出组件
        RemoveAssembly()
    抓住uaEx作为UnauthorizedAccessException
        投掷uaEx
    结束尝试

    昏暗的成功作为布尔= FALSE
    昏暗outputFileName作为字符串= Path.Combine(My.Computer.FileSystem.SpecialDirectories.Temp,my.dll)
    昏暗的结果作为CompilerResults

    昏暗codeProvider作为新的VB codeProvider()
    昏暗的参数作为新CompilerParameters()

    parameters.TreatWarningsAsErrors =假
    parameters.CompilerOptions =/优化
    parameters.TempFiles =新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的)

    结果= codeProvider.CompileAssemblyFromSource(参数,codeContents)

    _errorCount = results.Errors.Count

    如果_errorCount> 0然后
        成功=假

        有编译器错误
        昏暗的SB作为新的StringBuilder
        对于每个compileError作为CompilerError在results.Errors
            sb.AppendLine()
            sb.AppendLine(行号:&放大器; compileError.Line)
            sb.AppendLine(错误号码:&放大器; compileError.ErrorNumber)
            sb.AppendLine(错误消息:&放大器; compileError.ErrorText)
            sb.AppendLine()
        下一个

        _errorMessageContents = sb.ToString()
    其他
        成功= TRUE

        编译成功,现在产生的TLB(可选)
        成功= GenerateTypeLib()

        如果成功,那么
            键入LIB产生的,现在注册GAC
            尝试
                成功= RegisterAssembly()
            抓住EX为例外
                成功=假
            结束尝试
        结束如果
    结束如果

    返回成功
端功能

专用功能GenerateTypeLib()作为布尔
昏暗的成功作为布尔= FALSE

'    尝试
昏暗的ASM为[assembly] = [大会] .ReflectionOnlyLoadFrom(My.Computer.FileSystem.SpecialDirectories.Temp&安培;\ my.dll)
暗淡转换器新TypeLibConverter()
昏暗的事件处理程序作为新ConversionEventHandler()

昏暗的类型库作为UCOMICreateITypeLib = CTYPE(converter.ConvertAssemblyToTypeLib(ASM,My.Computer.FileSystem.SpecialDirectories.Temp和放大器;\ my.tlb,0,事件处理程序),UCOMICreateITypeLib)
typeLib.SaveAllChanges()

成功= TRUE
抓住EX为例外
成功=假
投掷前
结束Try

返回成功
端功能

公共功能RegisterAssembly()作为布尔
    昏暗的成功作为布尔= FALSE

    尝试
        昏暗的ASM为[assembly] = [大会] .LoadFile(Path.Combine(My.Computer.FileSystem.SpecialDirectories.Temp,my.dll))
        昏暗的regasm作为新RegistrationServices的()

        成功= regasm.RegisterAssembly(ASM,AssemblyRegistrationFlags.None)
    抓住EX为例外
        成功=假
        投掷前
    结束尝试

    返回成功
端功能

公用Sub RemoveAssembly()
    AppDomain.Unload(asmAppDomain)

    File.Delete(Path.Combine(My.Computer.FileSystem.SpecialDirectories.Tempmy.dll))
    'File.Delete(Path.Combine(My.Computer.FileSystem.SpecialDirectories.Tempmy.tlb))
结束小组

私人共享子LogLoadedAssemblies(appDomain__1作为AppDomain中)
    昏暗的SB作为新的StringBuilder

    sb.AppendLine(中的AppDomain加载的程序集:&放大器; appDomain__1.FriendlyName)
    对于每个loadedAssembly作为大会AppDomain.CurrentDomain.GetAssemblies()
        sb.AppendLine( - &放大器; loadedAssembly.GetName()名称。)
    下一个

    的MessageBox.show(sb.ToString())
结束小组

私人共享功能CurrentDomain_ReflectionOnlyAssemblyResolve(发件人为对象,ARGS作为ResolveEventArgs)作为大会
返回System.Reflection.Assembly.ReflectionOnlyLoad(args.Name)
端功能
末级
 

解决方案

这是我们处理这种自动安装的.NET安装程序类,具有装载同样的问题,并锁定该DLL在当前的AppDomain的方式,是执行注册一个新的AppDomain。

在我去的,但是,你可能会考虑使用一个进程调用REGSVR32一个额外的快捷键进行注册DLL默默的。

下面code是具体到我们的解决方案,但应该给你一个想法:

 '''<总结>
'''注册指定的文件,用在.Registration属性指定的机制
'''< /总结>
'''< PARAM NAME =sFileName>< /参数>
'''<说明>< /说明>
私人小组注册(BYVAL sFileName作为字符串)
    例外被忽略

    昏暗oDomain作为应用程序域=无
    尝试
        昏暗oSetup作为新System.AppDomainSetup()

        随着oSetup
            .ApplicationBase = ApplicationConfiguration.AppRoot
            .ConfigurationFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile
            .LoaderOptimization = LoaderOptimization.SingleDomain
            .DisallowBindingRedirects =假
            .Disallow codeDownload = TRUE
        结束与

        启动应用程序
        oDomain = AppDomain.CreateDomain(AutoUpdater,AppDomain.CurrentDomain.Evidence,oSetup)

        oDomain.CreateInstance(的GetType(FileRegistration).Assembly.FullName,的GetType(FileRegistration)的ToString,真实,Reflection.BindingFlags.Default,没有什么新的对象(){} sFileName,没什么,没什么,AppDomain.CurrentDomain.Evidence)
    捕捉theException作为例外
        '燮preSS的误差对最终用户
        调用reportError的(theException,真)
    最后
        如果oDomain状态并没有任何然后
            AppDomain.Unload(oDomain)
        结束如果
    结束尝试
结束小组
 

类FileRegistration:

 '''<总结>
'''这个类是用来注册.NET安装程序文件。此功能包含在其自己的类,因为它是
'''在一个单独的AppDomain推出以prevent载入文件到宿主应用程序域(其中锁
'''他们,使他们无法使用,直到宿主应用程序被关闭)。
'''< /总结>
'''<说明>< /说明>
公共类FileRegistration
    继承MarshalByRefObject的

    公共子新(BYVAL sFileName作为字符串)
        例外被忽略
        尝试
            使用oInstaller作为新System.Configuration.Install.AssemblyInstaller(sFileName,新的String(){/logfile=autoupdate.log})
                昏暗htSavedState作为新Collections.Hashtable()

                oInstaller.Install(htSavedState)
                oInstaller.Commit(htSavedState)
            结束使用
        捕捉theException作为例外
            '燮preSS的误差对最终用户
            调用reportError的(theException,真)
        结束尝试
    结束小组
 

I've got a simple VB.Net 4 WinForms application that does basic code generation. The code generation creates a DLL assembly perfectly fine, but each time the DLL is generated it needs to be registered programmatically with the GAC. The reason it must be registered is that it is a COM object that when deployed gets called via CreateObject from a VB6 application. Eww, I know.

All of this works fine: the DLL generation, registering programmatically and using the generated DLL from the VB6 application.

The problem is that my application that does the code generation can only generate the DLL once before the DLL is locked out by the process with no way to unlock it without stopping the EXE and starting it up again. This obviously prevents the user of the code generation tool from making a change and recompiling the DLL without restarting the application.

The code that causes the lock is the following (on the line defining the variable "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

I've tried throwing the assembly definition into a different AppDomain as I've seen in a number of articles on the web, but none of the implementations that I've come up with has worked. In fact, nearly all of them ended up with the generated assembly then being defined in BOTH of the AppDomains. I've also tried doing a ReflectionOnly assembly load but in order to the the register functions the assembly must be loaded in active mode not reflection mode.

The actual error that it throws is this wonderful gem:

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.

If anyone has an answer for me on what I can do to fix this, I'd be greatly appreciative! Like I said, it works great the first DLL compile but subsequent compiles of the DLL fail because the assembly is locked by the application process.

My full compiler class definition is below. I've left in some of the additional stuff I've tried, sorry for the clutter:

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
解决方案

The way that we handled this for automatically installing .Net installer classes, which has the same issue with loading and locking the DLL in the current appdomain, is to perform the registration in a new appdomain.

Before I get to that, however, one additional shortcut that you might consider is using a process to call regsvr32 to register to DLL silently.

The following code is specific to our solution, but should give you an idea:

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

Class 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

这篇关于编程注册生成VB.Net DLL组件没有锁定该DLL的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-05 22:37