Results 1 to 18 of 18

Thread: Load Assembly

  1. #1

  2. #2
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    111,221

    Re: Load Assembly

    I've never done this before myself, so I figure that you should be able to put the pices together as easily as I can. You'd call Assembly.Load, Assembly.GetTypes, Type.GetMethods and then MethodInfo.Invoke.
    Why is my data not saved to my database? | MSDN Data Walkthroughs
    VBForums Database Development FAQ
    My CodeBank Submissions: VB | C#
    My Blog: Data Among Multiple Forms (3 parts)
    Beginner Tutorials: VB | C# | SQL

  3. #3

    Thread Starter
    PowerPoster cicatrix's Avatar
    Join Date
    Dec 2009
    Location
    Moscow, Russia
    Posts
    3,654

    Re: Load Assembly

    Well, this all started when I tried to convert theory into practice.
    Basically, I tried to built something that supports plugins:

    I don't even want to enumerate the members because I know the one to invoke.

    I made this class library and compiled it:

    vb.net Code:
    1. Public Class CustomPlugin
    2.     Implements IPluginInterface
    3.  
    4.     Public Sub DoWork() Implements IPluginInterface.DoWork
    5.         MsgBox("Work is done by the plugin.")
    6.     End Sub
    7. End Class
    8.  
    9. Public Interface IPluginInterface
    10.     Sub DoWork()
    11. End Interface
    Now I need to invoke sub DoWork from my main app:


    vb.net Code:
    1. Imports System.Reflection
    2.  
    3. Public Class Form1
    4.  
    5.     Public Interface IPluginInterface
    6.         Sub DoWork()
    7.     End Interface
    8.  
    9.     Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    10.         Dim asm As Assembly = Assembly.LoadFrom("D:\VS Projects\PluginsDemo\DemoPlugin\bin\Release\DemoPlugin.dll")
    11.         Dim plugin As IPluginInterface = Nothing
    12.         For Each AsmType As Type In asm.GetTypes()
    13.             If AsmType.GetInterface("IPluginInterface") IsNot Nothing Then
    14.                 ' InvalidCastException on the following line:
    15.                 plugin = DirectCast(Activator.CreateInstance(AsmType), IPluginInterface)  
    16.             End If
    17.         Next
    18.         If Not (plugin Is Nothing) Then
    19.             plugin.DoWork()
    20.         End If
    21.  
    22.     End Sub
    23.  
    24. End Class


    Well, how do I get rid of the InvalidCastException or am I doing something wrong?

  4. #4
    Super Moderator Shaggy Hiker's Avatar
    Join Date
    Aug 2002
    Location
    Idaho
    Posts
    40,104

    Re: Load Assembly

    Here is what I am using to load up a bunch of dlls with classes that may or may not be plug-ins for this program (they implement the HISInCommon.IHISGeneral interface if they are), iterate throught the items, then add them to a list if they belong:
    Code:
    Public Sub InitDLLs()
           'Look for the directory that holds the dlls.
            If IO.Directory.Exists("C:\IFWIS\HIS\") Then
                For Each fl As String In IO.Directory.GetFiles("C:\IFWIS\HIS\", "*.dll")
                    Try
                        Dim aDLL As System.Reflection.Assembly = System.Reflection.Assembly.LoadFile(fl)
    
                        If aDLL IsNot Nothing Then
                            Dim tArr As Type() = aDLL.GetExportedTypes
    
                            For Each t As Type In tArr
                                If t.GetInterface("HISInCommon.IHISGeneral") IsNot Nothing Then
                                    Dim o As Object = aDLL.CreateInstance(t.FullName)
    
                                    If o IsNot Nothing Then
                                        CType(o, HISInCommon.IHISGeneral).Initialize(mConString, mEventRaiser)
                                        If CType(o, HISInCommon.IHISGeneral).IsInitialized Then
                                            mIList.Add(New MenuInterfaceLink(CType(o, HISInCommon.IHISGeneral)))
                                        End If
                                    End If
                                End If
                            Next
                        End If
                    Catch ex As Exception
    
                    End Try
                Next
            End If
        End Sub
    My usual boring signature: Nothing

  5. #5

    Thread Starter
    PowerPoster cicatrix's Avatar
    Join Date
    Dec 2009
    Location
    Moscow, Russia
    Posts
    3,654

    Re: Load Assembly

    I tied that. The same thing. I just can't cast it into my interface:

    Code:
     Dim tArr As Type() = asm.GetExportedTypes
    
    
            For Each t As Type In tArr
                If t.GetInterface("IPluginInterface") IsNot Nothing Then
                    Dim o As Object = asm.CreateInstance(t.FullName)
    
                    If o IsNot Nothing Then
                        CType(o, IPluginInterface).DoWork() ' InvalidCastException
                    End If
                End If
            Next

  6. #6
    Super Moderator Shaggy Hiker's Avatar
    Join Date
    Aug 2002
    Location
    Idaho
    Posts
    40,104

    Re: Load Assembly

    Ok, now THAT's interesting.

    To put it lightly, I have zero good suggestions here, but am very curious about the answer. The steps I would try you may already have tried...and they may be useless anyways. The first thing I would do would be to put a breakpoint on the If statement with the t.GetInterface. When I hit the breakpoint, I would use Shift+F9 to look at t.GetInterfaces (or whatever it is called, it's the method that enumerates all interfaces on the class).

    However, that seems unlikely to show anything of interest. So let's abandon that thought.

    The way I have this set up is that the interface is in a dll that is included into every plugin, as well as the main project. Is that how you have it set up?
    My usual boring signature: Nothing

  7. #7

    Thread Starter
    PowerPoster cicatrix's Avatar
    Join Date
    Dec 2009
    Location
    Moscow, Russia
    Posts
    3,654

    Re: Load Assembly

    Quote Originally Posted by Shaggy Hiker View Post
    Ok, now THAT's interesting.

    To put it lightly, I have zero good suggestions here, but am very curious about the answer. The steps I would try you may already have tried...and they may be useless anyways. The first thing I would do would be to put a breakpoint on the If statement with the t.GetInterface. When I hit the breakpoint, I would use Shift+F9 to look at t.GetInterfaces (or whatever it is called, it's the method that enumerates all interfaces on the class).
    It yields only one:
    DemoPlugin.CustomPlugin


    Quote Originally Posted by Shaggy Hiker
    The way I have this set up is that the interface is in a dll that is included into every plugin, as well as the main project. Is that how you have it set up?
    Yes, you can see my first post.
    My 'plugin' is a class library that consists of a public interface IPluginInterface and a public method DoWork.

    Here's the complete listing:
    Code:
    Public Class CustomPlugin
        Implements IPluginInterface
    
        Public Sub DoWork() Implements IPluginInterface.DoWork
            MsgBox("Work is done by the plugin.")
        End Sub
    End Class
    
    Public Interface IPluginInterface
        Sub DoWork()
    End Interface
    It is compiled into a dll and gets loaded by the main application which also has the public IPluginInterface declared.

  8. #8

    Thread Starter
    PowerPoster cicatrix's Avatar
    Join Date
    Dec 2009
    Location
    Moscow, Russia
    Posts
    3,654

    Re: Load Assembly

    One thing I've noticed. Here, in the break mode when the execution point is set at the CType:

    Code:
    Dim o As Object = asm.CreateInstance(t.FullName)
    
    If o IsNot Nothing Then
    ' Breakpoint line:
        CType(o, IPluginInterface).DoWork() ' InvalidCastException
    End If
    If I type in the Immediate window:
    Code:
    o.DoWork
    The methods works and the message box is shown. But I can't cast my object to the interface I can use and the option strict on disallows late binding

  9. #9
    Super Moderator Shaggy Hiker's Avatar
    Join Date
    Aug 2002
    Location
    Idaho
    Posts
    40,104

    Re: Load Assembly

    It is compiled into a dll and gets loaded by the main application which also has the public IPluginInterface declared.
    I have a lolcat that could go with this comment, but since this is a serious forum I'll just add the text:

    Duuuude....wait...what?

    If the interface is declared in the dll, and re-declared in the main project, they aren't the same interface no matter what they look like.
    My usual boring signature: Nothing

  10. #10

    Thread Starter
    PowerPoster cicatrix's Avatar
    Join Date
    Dec 2009
    Location
    Moscow, Russia
    Posts
    3,654

    Re: Load Assembly

    Well, this makes sense I suppose but...
    if I remove the interface declaration from my class library then GetInterface method won't find it. If I remove the interface declaration from my main app then what type should I convert the plugin to?

  11. #11
    Super Moderator Shaggy Hiker's Avatar
    Join Date
    Aug 2002
    Location
    Idaho
    Posts
    40,104

    Re: Load Assembly

    The simple answer would be:

    DemoPlugin.IPluginInterface

    assuming that the dll name is DemoPlugin. However, that's a bad answer, so it doesn't matter. I ran into this problem when moving objects through serialization between different projects. I think the assembly is attached to the type (it is for serialization), so you can't declare the same type in two different assemblies and have them be the same. You have to use one or the other. In the case of a plugin, having the interface type declared in the plugin totally defeats the purpose of the plugin, because you'd have a hard time creating more than one plugin.

    What I am doing is that the interface (and a few other useful things, in my case) is declared in one dll called HISInCommon. Each plugin dll references the HISInCommon to get the interface, and so does the main program. It does mean that there is an extra dll floating around in addition to any plugins, but it is the only way that I know of to have all the assemblies share the same object.

    I should add that this means that all of my interfaces are:

    HISInCommon.IHISGeneral

    regardless of which project they are in. They are all referencing that one common interface in its own dll accessible to each assembly.
    My usual boring signature: Nothing

  12. #12

    Thread Starter
    PowerPoster cicatrix's Avatar
    Join Date
    Dec 2009
    Location
    Moscow, Russia
    Posts
    3,654

    Re: Load Assembly

    Hmm, having a third dll is not what I had in mind when started researching this issue.
    What I mean is that I can distribute login much later than the original app and having an extra dll with references is simply an equivalent of a direct reference from plugin to the base app. A dll is just an unnecessay layer between them. I would prefer not to use references at all.
    What I understood about plugins is that both a plugin and the base app must expose some interface through which they can communicate. I thought that this is what interfaces are designed for. Apparently I was wrong and Interface is just another reference data type and simply implementing an interface doesn't mean I can cast one implementation into another.
    So, let's drop the interfaces, can I invoke some method by its name?

  13. #13
    Super Moderator Shaggy Hiker's Avatar
    Join Date
    Aug 2002
    Location
    Idaho
    Posts
    40,104

    Re: Load Assembly

    Yeah, look into CallByName. I have little experience with it, but have used it.

    What you said about the interfaces makes more sense than I had first thought. Frankly, I was taking the third dll route because I felt I had to (and I do because of things other than the interface). However, I have just been playing with Type.GUID. This shows, in case there was any doubt, that a class implementing a common interface still has a unique GUID. The type id is not tied to the interface, but to the underlying class, which makes sense. So why would the declaration of the interface carry other baggage?

    If you are willing to pursue the interface question a bit further, then reconsider what I suggested in the first lines of post #11. It does make sense that something declared in a dll should be called using the convention:

    <dll name>.<object name>

    just because of namespace rules. Otherwise you would have to be VERY careful about what you named anything in a dll lest it conflict with another object with the same name anywhere else in the project. This has to be true of interfaces, just as much as it does with objects, and for the same reason.

    That's probably enough of a problem to keep you away from the interface route, but for every dll you could always cast it to the correct type with:

    <dll name>.<interface name>

    whenever you needed it. Seems like a total pain though, as the only way I can see to do that is to maintain a structure with the dllname and use that to build the name to cast to each time you wanted to use it.

    Of course, you could probably build a class in the main project that took the dll name in the constructor, and had the same methods as the interface. Every method would be a wrapper of the call to the interface such that the class DoWork method would be implemented like this:
    Code:
    Public Class ShellGame
     Private myDLLName as string
     Private myDLL as Object
    
     Public Sub New (dllName as string, dllObject as Object)
      myDLLName = dllName
      myDLL = dllObject
     End Sub
    
     Public Sub DoWork
       Dim t as Type = GetInterface(myDLLName & ".IPluginInterface")
       
       CType(myDLL,t).DoWork()
     End Sub
    
    End Class
    Having written that, which is lacking lots of safety features, I realized that the whole thing is silly, but I decided not to re-write. If that class was changed to implement the main project interface, as it should be, then much of that work can be done in the constructor, and all dll interfaces can be shelled into a main project interface.
    My usual boring signature: Nothing

  14. #14
    PowerPoster techgnome's Avatar
    Join Date
    May 2002
    Posts
    34,687

    Re: Load Assembly

    an Interface is more than a reference type. It's a contract between the caller and the implementation, to guarantee that the implementor will contain a given set of methods/functions/properties. If I have an Interface, ICar, any implementation of ICar is going to have a StartEngine method... doesn't matter if it's the Bugatti implementation or a VW implementation or a Prius. (granted, that doesn't guarantee that the ApplyBrakes method actually has the proper implementation, but the method is at guaranteed to exist (yes, I know, cheap shot)).

    Meanwhile, that interface definition of ICar has to exist somewhere where both the base app and the implementing class can access it, so that both can agree on the same signatures. Putting it in a third assembly makes sense, then both can reference it. Additionally, if another developer needs to create another plugin, then all they have to do is reference the interface assembly and then implement it. Other wise, it sounds like you're trying to get the implementations to each define their own interfaces, which may or may not agree with what the base app is expecting.

    -tg
    * I don't respond to private (PM) requests for help. It's not conducive to the general learning of others.*
    * I also don't respond to friend requests. Save a few bits and don't bother. I'll just end up rejecting anyways.*
    * How to get EFFECTIVE help: The Hitchhiker's Guide to Getting Help at VBF - Removing eels from your hovercraft *
    * How to Use Parameters * Create Disconnected ADO Recordset Clones * Set your VB6 ActiveX Compatibility * Get rid of those pesky VB Line Numbers * I swear I saved my data, where'd it run off to??? *

  15. #15

    Thread Starter
    PowerPoster cicatrix's Avatar
    Join Date
    Dec 2009
    Location
    Moscow, Russia
    Posts
    3,654

    Re: Load Assembly

    I understood this part about interfaces but it doesn't seem to be helping with the result I'm trying to achieve.

    The concept of Win32 interfaces might have mislead me into thinking that I can do the same things with VS.Net. I admit that I have never actually used interfaces in my C++ programming for win32 but I've read about them. Apparently, they are not suitable for the task.

    All I need is actually load a standalone assembly (with no references present), get its methods and, if some sings (which I thought the interface will help me with) will show me that this assemby is actually a plugin to my application, invoke a method by the name.

  16. #16
    PowerPoster techgnome's Avatar
    Join Date
    May 2002
    Posts
    34,687

    Re: Load Assembly

    Two ways I can think of to do this. Not care about what interface is or isn't implemented. Load the assembly, query its methods, if you find the method you're looking for, blindly invoke it. This can be done with reflection.

    The second way is similar, again, use reflection to query the loaded assembly, this time look for a property that exposes something like an application key. If the value matches what you are looking for, then invoke the method.

    I guess it's the same way, really.... it's just that the second idea has the added security that the developer would have to be given a "key" of sorts to allow your app to load the assembly. Prevents you from accidentally running a dll, simply because it had the same method name as what you are looking for.

    -tg
    * I don't respond to private (PM) requests for help. It's not conducive to the general learning of others.*
    * I also don't respond to friend requests. Save a few bits and don't bother. I'll just end up rejecting anyways.*
    * How to get EFFECTIVE help: The Hitchhiker's Guide to Getting Help at VBF - Removing eels from your hovercraft *
    * How to Use Parameters * Create Disconnected ADO Recordset Clones * Set your VB6 ActiveX Compatibility * Get rid of those pesky VB Line Numbers * I swear I saved my data, where'd it run off to??? *

  17. #17
    Super Moderator Shaggy Hiker's Avatar
    Join Date
    Aug 2002
    Location
    Idaho
    Posts
    40,104

    Re: Load Assembly

    I agree with TG that those appear to be the ways to work this without interfaces, but I prefer my shell game class to either of those options. For one thing, it does give you a way to identify proper plugins. However, it also becomes up to convention as to whether or not the interface in the plugin actually does have all the methods of the interface in the main project.
    My usual boring signature: Nothing

  18. #18

    Thread Starter
    PowerPoster cicatrix's Avatar
    Join Date
    Dec 2009
    Location
    Moscow, Russia
    Posts
    3,654

    Re: Load Assembly

    I should devise some other means of identifying a plugin then. I think that having the ability of calling a single main method is perfectly enough for my needs. The rest of the job will be done by the plugin.

    The second quesion is about 'Binder' object. What is it? How do I prepare one?
    Here's an overload of InvokeMember:
    Code:
    Type..::.InvokeMember Method (String, BindingFlags, Binder, Object, array<Object>[]()[])
    There is some demonic example here that doesn't illustrate anything for me.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width