通过AppDomain读取.NET生成的DLL中信息

DLL文件,取出他的Assembly信息可以使用Reflection.Assembly.LoadFrom(Path)句来实现。但是这样读取之后,如果我的程序不退出,DLL就会被我的程序死,不能修改或除了。了解决这样问题,我AppDomain用程序域)来实现

由于我们通过AppDomain来操作,所以我们的信息必须要支持跨应用程序域的访问。为此,我们需要做一个继承自MarshalByRefObject的类来进行我们的核心操作Reflection.Assembly.LoadFrom(Path)。这样在另外一个AppDomain下面我们就可以通过这个类操作Reflection.Assembly.LoadFrom(Path),并且把相关的信息返回回来。具体代码如下。

        Private NotInheritable Class AssemblyLoader

            Inherits MarshalByRefObject

 

            Private m_Asm As Reflection.Assembly

 

            Public Sub LoadAssemblyFile(ByVal Path As String)

                If IO.File.Exists(Path) = True Then

                    m_Asm = Reflection.Assembly.LoadFrom(Path)

                End If

            End Sub

 

        End Class

下面我们再做一个类来专门调用这个类,读取DLL文件的Assembly信息。这个类没有什么特别的要求,从Object继承就可以了。然后我们需要一个AppDomain(应用程序域)Private m_ap As AppDomain

下面我们建立一个函数,它的返回值是我们刚刚建立的那个继承自MarshalByRefObject的类,让我们能够调用Reflection.Assembly.LoadFrom(Path)来读取Assembly信息。

        Private Function CreateAssemblyLoaderInstanse(Optional ByVal DomainName As String = "") As AssemblyLoader

            Dim objh As System.Runtime.Remoting.ObjectHandle

            Dim obj As Object

            Dim al As AssemblyLoader

            Try

                If DomainName.Trim = "" Then

                    DomainName = DNAME_DEFAULT & Rnd()

                End If

                AddHandler AppDomain.CurrentDomain.AssemblyResolve, AddressOf OnResolveEventHandler

                m_ap = AppDomain.CreateDomain(DomainName)

                objh = m_ap.CreateInstanceFrom(System.Reflection.Assembly.GetExecutingAssembly().Location, GetType(AssemblyLoader).FullName)

                obj = objh.Unwrap()

                al = CType(obj, AssemblyLoader)

            Catch ex As Exception

                al = Nothing

            End Try

            Return al

        End Function

前几行代码是为了设定应用程序域的名字的,没有什么特别的。核心的语句是

m_ap = AppDomain.CreateDomain(DomainName)

objh = m_ap.CreateInstanceFrom(System.Reflection.Assembly.GetExecutingAssembly().Location, GetType(AssemblyLoader).FullName)

obj = objh.Unwrap()

al = CType(obj, AssemblyLoader)

首先我们通过AppDomain.CreateDomain(DomainName)建立了自己的AppDomain。然后我们在这个AppDomain下面通过CreateInstanceFrom方法建立AssemblyLoader类的实例。最后通过ObjectHandle.Unwrap方法返回被包装的对象。最后CType成我们的AssemblyLoader

这样,这个AssemblyLoader就被建立在了一个新的AppDomain里面,而AssemblyLoader的所有操作都是在这个AppDomain中,通过MarshalByRefObject返回给我们主AppDomain

我们直接调用al.LoadAssemblyFile(Path)就可以读取Assembly信息了。

当我们操作完了这个DLL之后,我们通过AppDomain.Unload(m_ap)卸载这个AppDomain,这样这个DLL的读写LOCK就会解除了。这样就解决了我们的问题。

相关的代码如下。

        Private Function OnResolveEventHandler(ByVal sender As Object, ByVal args As ResolveEventArgs) As System.Reflection.Assembly

            Dim MyAssembly As System.Reflection.Assembly

            If args.Name = System.Reflection.Assembly.GetExecutingAssembly().FullName Then

                MyAssembly = System.Reflection.Assembly.LoadFrom(System.Reflection.Assembly.GetExecutingAssembly().Location)

            End If

            Return MyAssembly

        End Function

 

        Private Sub Unload()

            RemoveHandler AppDomain.CurrentDomain.AssemblyResolve, AddressOf OnResolveEventHandler

            If Not m_ap Is Nothing Then

                AppDomain.Unload(m_ap)

            End If

        End Sub

但是需要我们注意的是,跨应用程序域的成员通信只支持简单数据类型,或者是从MarshalByRefObject继承的。也就是说,我们通过AssemblyLoader得到的只能是诸如IntegerString这样的东西。所以我们在使用的时候,需要在AssemblyLoader里面做好读取我们需要信息的方法,通过简单数据类型来返回。这也就决定了我们不可能使用这个办法制作出公用性很强的类。

posted @ 2005-03-21 16:17  妖居  阅读(1516)  评论(1编辑  收藏  举报