|
-
Mar 13th, 2010, 11:37 PM
#1
Load Assembly
Can somebody show an example of loading a standalone assembly, enumerating its methods and invoking one?
-
Mar 14th, 2010, 01:21 AM
#2
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.
-
Mar 14th, 2010, 09:38 AM
#3
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:
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
Now I need to invoke sub DoWork from my main app:
vb.net Code:
Imports System.Reflection Public Class Form1 Public Interface IPluginInterface Sub DoWork() End Interface Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load Dim asm As Assembly = Assembly.LoadFrom("D:\VS Projects\PluginsDemo\DemoPlugin\bin\Release\DemoPlugin.dll") Dim plugin As IPluginInterface = Nothing For Each AsmType As Type In asm.GetTypes() If AsmType.GetInterface("IPluginInterface") IsNot Nothing Then ' InvalidCastException on the following line: plugin = DirectCast(Activator.CreateInstance(AsmType), IPluginInterface) End If Next If Not (plugin Is Nothing) Then plugin.DoWork() End If End Sub End Class
Well, how do I get rid of the InvalidCastException or am I doing something wrong?
Last edited by cicatrix; Mar 14th, 2010 at 09:54 AM.
-
Mar 14th, 2010, 01:27 PM
#4
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
 
-
Mar 14th, 2010, 02:17 PM
#5
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
-
Mar 14th, 2010, 08:35 PM
#6
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
 
-
Mar 15th, 2010, 01:40 AM
#7
Re: Load Assembly
 Originally Posted by Shaggy Hiker
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
 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.
-
Mar 15th, 2010, 06:27 AM
#8
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:
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
-
Mar 15th, 2010, 09:49 AM
#9
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
 
-
Mar 15th, 2010, 10:58 AM
#10
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?
-
Mar 15th, 2010, 11:10 AM
#11
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
 
-
Mar 15th, 2010, 11:21 AM
#12
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?
-
Mar 15th, 2010, 11:51 AM
#13
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
 
-
Mar 15th, 2010, 12:15 PM
#14
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
-
Mar 15th, 2010, 01:09 PM
#15
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.
-
Mar 15th, 2010, 02:03 PM
#16
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
-
Mar 15th, 2010, 04:18 PM
#17
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
 
-
Mar 16th, 2010, 01:56 AM
#18
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
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|