How to convert a type, loaded from one project, to an interface - vb.net

Prerequisites
.NET environment
A Common assembly with an interface IModule
Main project, referencing Common
Implementor project, referencing Common, but not referenced from Main
When everything is built, the Common.dll is present in both Main and Implementor.
Now the Main project tries to load the class implementing IModule at runtime. What I could achieve so far:
Dim asm = Assembly.LoadFrom(asmFile)
For Each asmType in asm.GetExportedTypes()
If asmType.IsClass AndAlso
asmType.GetInterfaces().Any(Function(i) i.Name = GetType(IModule).Name) Then
Dim handle = AppDomain.CurrentDomain.CreateInstanceFrom(asmFile, asmType.FullName)
Dim inst = CType(handle.Unwrap(), IModule) ' EXCEPTION
End If
Next
So I can load the Implementor assembly and find the type implementing IModule. But I can't create an instance of it such that I can cast it to my local IModule. Is this at all possible?
Workaround
I found a workaround - in Implementor project, click on reference to Common and clear "Copy Local" flag. Then I can even use simpler code, like IsAssignableFrom(). But is this the only way? What if I get a DLL from third party, where the IModule is compiled into it?

EDIT:
Assembly.LoadFrom loads the first found matching assembly in a directory tree (via the so called Probing Path). So if you have your Common DLLin folder A and the updated Common DLL is in folder A\B then the one in folder A is taken (if both dlls have the same name).
From MSDN:
The load-from context allows an assembly to be loaded from a path not
included in probing, and yet allows dependencies on that path to be
found and loaded because the path information is maintained by the
context.
The LoadFrom method has the following disadvantages.Consider using
Load instead.
If an assembly with the same identity is already loaded, LoadFrom returns the loaded assembly even if a different path was specified.
If an assembly is loaded with LoadFrom, and later an assembly in the load context attempts to load the same assembly by display name,
the load attempt fails.This can occur when an assembly is
de-serialized.
If an assembly is loaded with LoadFrom, and the probing path includes an assembly with the same identity but a different location,
an InvalidCastException, MissingMethodException, or other unexpected
behavior can occur.
Original Answer:
Use Activator.CreateInstance to create the object and typeof to check if it implements the Interface :
Dim a As assembly = Assembly.LoadFrom(asmFile)
Dim concreteModule As IModule = Nothing
For each type In a.GetExportedTypes().Where(Function(x) x.IsClass)
Dim o = Activator.CreateInstance(type)
If TypeOf o Is IModule
concreteModule = DirectCast(o, IModule)
Exit For
End If
Next
Remark:
You wrote: But I can't create an instance of it such that I can cast it to my local IModule.
The concrete object must implement the Interface you cast to. I donĀ“t know if I understood you correctly but casting from a Interface IModule in a 3rd party dll to a different Interface IModule* in your local dll will not work (unless your local interface implements the other).

Related

Matching Roslyn SourceMemberMethodSymbol with a 'RetargetingMethodSymbol'

I've been putting some 'find references' code together using Roslyn to search for all method declarations that match a particular signature, and then locate all uses of those methods elsewhere.
It's working in 99% of cases, but I've got an issue where an InvocationExpressionSyntax.Symbol is an instance of Microsoft.CodeAnalysis.VisualBasic.Symbols.Retargeting.RetargetingMethodSymbol instead of a regular Microsoft.CodeAnalysis.VisualBasic.Symbols.SourceMemberMethodSymbol. As a consequence this particular call to a target method isn't found (using ISymbol.Equals, which uses reference equality). RetargetingMethodSymbol has an UnderlyingMethod property whose value is the target method I'd expect, but this type is internal and that property isn't exposed.
What is a RetargetingMethodSymbol, and how can I see if it corresponds to a MethodBlockSyntax.Symbol?
What is a RetargetingMethodSymbol?
Consider a method M(object o) that is defined in project A, which targets .NET 2.0.
Project B targets .NET 4.0, and has a reference to A. In the context of project B, M will be wrapped in a RetargetingMethodSymbol, since the object that it refers to in this context isn't the same one that it refers to in the context of A.
How can I see if it corresponds to a MethodBlockSyntax.Symbol?
I don't know what you mean by MethodBlockSyntax.Symbol, but the VS IDE code uses SymbolFinder.FindSourceDefinitionAsync() to find the "original" symbol in cases like this (and also if A was written in C# and B in VB or vice versa).

VB.NET Automatically include DLLs in specific folder

I have a project where I have a directory called plugins/ which will contain multiple DLLs.
As an example, I will have two (2) DLLs in my plugins/ directory: Visual.dll and Momen.dll
Each of those will be a Class, Visual.dll will have the Class name Visual and Momen.dll will have the Class name Momen.
I need to make a loop that will loop through all DLL files in my plugins/ directory; once in that loop, it will obviously know the file is Visual.dll or Momen.dll. First, it will need to include the DLLs (just as if I added them as References to my Project) so that I can use them. If the loop is at Visual.dll, I will then need it to create an instance of the Visual Class, and then execute a method called Run()
I'm a PHP developer, and relatively new to VB.NET, in PHP I'd be able to do something like, which would create a new instance of my Visual Class (while passing a few arguments), then execute the Run() method:
$className = "Visual";
$instance = new $className("arg1", "arg2");
$instance->Run();
I appreciate any help.
Thank you
If the DLLs are .NET assemblies, then you can load them with Assembly.LoadFile. That will give you a reference to an Assembly object.
You can use the assembly's GetExportedTypes method to view public types in the assembly, or the GetType overload that takes a string parameter to get a type from the assembly based on its name.
From there, you should be able to use an appropriate overload of Activator.CreateInstance to create an instance of the class. From there, you should also be able to find and run its Run method through reflection.
Edit This is untested, but something like this might work (or be close to working):
Dim plugin As Assembly = Assembly.LoadFile("test.dll")
Dim pluginType As Type = plugin.GetType("Test")
Dim instance As Object = Activator.CreateInstance(pluginType)
Dim runMethod As MethodInfo = pluginType.GetMethod("Run")
Dim param1 As String = "Hello"
Dim param2 As String = "World"
runMethod.Invoke(instance, New Object() {param1, param2})
If you're going to do much with plugins other than just load and run a method, then it might be worthwhile to look for a plugin framework to use.

Getting current file

I know in vb.net you can use System.Reflection.MethodInfo.GetCurrentMethod.ToString to get the name of the current method you are in. However, is there a way to use System.Reflection... to get the name of the current file you are in?
So if you had a file in the project named blah.vb I would want System.Reflection... to return blah.vb
Is this possible?
You can use System.Reflection.Assembly to find the file name of the current assembly. There are several applicable methods to choose from:
GetEntryAssembly - Returns the assembly that started the process (the executable)
GetCallingAssembly - Returns the assembly that called the current method
GetExecutingAssembly - Returns the assembly in which the current method resides
I suspect that what you want is GetExecutingAssembly. All of those methods return an Assembly object through which you can get the file path, like this:
Dim myFilePath As String = System.Reflection.Assembly.GetExecutingAssembly().Location
For what it's worth, if you need get the file name of the executable, but it's not a .NET assembly (because you're in a .NET library invoked via COM), then the above method won't work. For that, the best option would be to grab the first argument from the command line, like this:
Dim myComExeFile As String = Environment.GetCommandLineArgs()(0)

Matlab 2012a, static method invocation, not recognizing class outside current folder

I have a class Ellipse (handle, inherits from other class), that has one static method called createFromGaussian. It is located in a remote folder, that I add to Matlab path.
The thing is that, if I try to invoke the static function BEFORE creating any Ellipse object, it fails:
>> Ellipse.createFromGaussian(arg1,arg2)
Undefined variable "Ellipse" or class "Ellipse.createFromGaussian".
It works if I try any of the following things:
I change current directory to that in which Ellipse.m file is located
Working from a remote directory, I create an Ellipse object beforehand:
>> Ellipse()
[C=, axis=[0.0,0.0], angle=0.0]
>> Ellipse.createFromGaussian([],2)
Is this supposed to be this way? The error message sounds weird to me: of course it cannot find variable "Ellipse" or class "Ellipse.createFromGaussian"! It should find "Ellipse" class
So the Ellipse classdef file, and the function file, are in the same folder called #Ellipse, and the PARENT of the #Ellipse folder is on the path? That is what Matlab requires for it's system to work.
From the the ML help : "You must use an #-folder if you want to use more than one file for your class definition. Methods defined in separate files match the file name to the function name and must be declared in the classdef file."

Executing a function in an appdomain

Given a .NET DLL that consists of a class "Place" and a function "Where" that returns an integer; I need to load the dll into an application domain, execute the function and unload the application domain.
Dim domain As AppDomain = AppDomain.CreateDomain("Executor")
Dim buffer() As Byte = IO.File.ReadAllBytes("c:\path\Locator.dll")
Dim asy As Assembly = domain.Load(buffer)
Dim obj As [Object] = asy.CreateInstance("Locator.Place")
Dim method As MethodInfo = obj.GetType.GetMethod("Where")
Dim result as Integer = method.Invoke(obj, New [Object]() { 1 })
AppDomain.Unload(domain)
This line fails:
Dim asy As Assembly = domain.Load(buffer)
With this error message:
'Could not load file or assembly 'Place, Version=1.0.0.0, Culture=neutral, PublicKeyToken-null' or one of it's dependencies. The System Cannot find the specified file.'
The file is in the buffer, so I'm guessing it's a dependancy .dll. However, it should find those in the base program directory.
Any ideas as to the cause of the error?
Any tested sample code for loading an assembly into an AppDomain, Execting a function, then unloading the AppDomain would be appreciated.
(BTW, I have googled and have not found any useful samples.)
You are correct in stating that the error is due to a missing reference. The reference most likely can't be resolved because of how you are loading the assembly. Since you are loading from a Byte Array, the Assembly.Location will not point to the location of the dll. Since the dll you are referencing is not in the GAC, it will not be able to find the referenced assembly. Try loading the assembly directly from file, and not loading into a byte array first.
If you want to know what dependency could not be loaded, try using fuslogvw. Check http://msdn.microsoft.com/en-us/library/e74a18c4(VS.71).aspx
I found the explanation on link text pretty good. It illustrates some pitfalls and provides sample code that should be easily translated into VB.NET.
I hope this helps.