How do I Import Dll and call sub?

  • Thread starter Thread starter Nicolas
  • Start date Start date
N

Nicolas

I created in VB.Net two dlls projects. dllA and dllB both will have the same
subs/functions name but do different things.
They have classes with interfaces as seen below.

How from a third dll project (dllC) can I call those subs
Seems that I always missed an entrypoint. or something.
Those dlls are all store in the same folder as the dllC.

Thank you very much for the help.

Code EXAMPLE:
dllA
Namespace NA
Interface iA
sub doThis(byVal a string)
End Interface

Class cA
implements iA

sub New(myParam as string)
'..... do something
end sub

private sub doThis(byVal a as string) implements iA.doThis
'do something with a
end sub

end Class
end Namespace
--------------------------------------
dllB
Namespace NB
Interface iB
sub doThis(byVal b string)
End Interface

Class cB
implements iB

sub New(myParam as string)
'..... do something
end sub

private sub doThis(byVal b as string) implements iB.doThis
'do something with b
end sub

end Class
end Namespace
--------------------------------------
dllC
Namespace C
Class C
dim thisDLL as string

'Set thisDll with the name that correspond to the needs
'Assuming that I want dllB
thisDll = "dllB"
'WHAT to Do from here to be able to call that dll and that sub?

myDll.doThis(myvalue)

end Class
end Namespace
 
Nicolas said:
I created in VB.Net two dlls projects. dllA and dllB both will have the same
subs/functions name but do different things.
They have classes with interfaces as seen below.

How from a third dll project (dllC) can I call those subs
Seems that I always missed an entrypoint. or something.
Those dlls are all store in the same folder as the dllC.

Thank you very much for the help.

Code EXAMPLE:
dllA
Namespace NA
Interface iA
sub doThis(byVal a string)
End Interface

Class cA
implements iA

sub New(myParam as string)
'..... do something
end sub

private sub doThis(byVal a as string) implements iA.doThis
'do something with a
end sub

end Class
end Namespace
--------------------------------------
dllB
Namespace NB
Interface iB
sub doThis(byVal b string)
End Interface

Class cB
implements iB

sub New(myParam as string)
'..... do something
end sub

private sub doThis(byVal b as string) implements iB.doThis
'do something with b
end sub

end Class
end Namespace
--------------------------------------
dllC
Namespace C
Class C
dim thisDLL as string

'Set thisDll with the name that correspond to the needs
'Assuming that I want dllB
thisDll = "dllB"
'WHAT to Do from here to be able to call that dll and that sub?

myDll.doThis(myvalue)

end Class
end Namespace

In project C, set a reference to the assemblies (=dlls) that you want to
use (other than the common base class System.Object). Then use the
classes and methods like those in project C.

If two classes have methods with the same name, they still have nothing
in common. You have to implement the _same_ interface in both classes.
Then, at runtime, you can call the method, no matter if it's a ClassA or
a ClassB object. For this purpose you can create a common base dll (dll
D) that provides the interface. Implement the interface in classes in
dll A and dll B. At runtime you can then decide which object to create:

dim myObject as iD 'interface from dll D

if condition then
myObject = new ClassA
else
myobject = new ClassB
end if

myobject.doThis
 
Thanks
that solution is not really working for my project because I may add later
on 2, 3 10 more dlls with the same structure but not wanted to recompile the
main dllC, but just rather add those new dlls into the folder with the other
one. This as to be really dynamic since I wont be able to recompile
everything all the time. For example the Main application may only have dllC
dllA,dllF and in another case this main application may only have dllC dllA,
dllB, dllD

Then when I got to dllC the value thisDll will be recieving another dll
name like dllG for example
in dllC I'll have the sub to launch this.
sub LaunchNewDll(thisDll as string)
myDll.doThis(myvalue)
end Sub

Again thank you.
 
Nicolas said:
Thanks
that solution is not really working for my project because I may add later
on 2, 3 10 more dlls with the same structure but not wanted to recompile the
main dllC, but just rather add those new dlls into the folder with the other
one. This as to be really dynamic since I wont be able to recompile
everything all the time. For example the Main application may only have dllC
dllA,dllF and in another case this main application may only have dllC dllA,
dllB, dllD

Then when I got to dllC the value thisDll will be recieving another dll
name like dllG for example
in dllC I'll have the sub to launch this.
sub LaunchNewDll(thisDll as string)
myDll.doThis(myvalue)
end Sub

Again thank you.

If you don't know the dlls at design time, you can use
System.Reflection.Assembly.LoadFrom. It returns an Assembly object. You
can get the types inside the assembly by calling the GetType/GetTypes
methods. Then create instances of the types by calling
Activator.CreateInstance. If you type cast the result to the common
interface, you can then call it's members. The compiler is able to
resolve the calls. If you don't have a common interface you must use
reflection. That's slow and not recommended because the compiler can not
do any checks. To call a method using reflection, call the Type's
InvokeMember method. See [F1] for more about reflection.
 
Rather than creating two time the "same" interface (which is then not the
same) you could create a unique interface and have both classes implementing
this same interface.

It you want then to reference both of them see Armin response.

Else you can use Assembly.LoadFile to load the DLL, and iterate through
types to find out which class(es) implements this interface. Then you can
use Assembly.CreateInstance to create an instance.

As you are using a single interface you'll be able then to call all methods
defined on this interface (ie. you have a Dim o As ITest, o being created
using CreateInstance)...

Also 2.0 as a whole infrastructure to handle complex plug in scenarii
(System.AddIns) that is perhaps overkill but might worth for complex, long
run scenarios...
 
Thanks, but I still need help,
I still did not get it to work regardless which technic I used. at this
point I got the error "Non-static method requires a target"
I place the code sample that I made so far and I don't know what and where
it's wrong
The idea is that later on I may just place on the computer running this
application more dlls in the app folders and I don't want to recompile the
entire thing since other computer may only need those one.
Deployment would be like here is the main application and you want this
and/or this modules only.

Thank you for helping me.

--------------------------------------------------------------------------------
CODE SAMPL
--------------------------------------------------------------------------------
Imports System
Imports System.Reflection
Imports System.Reflection.Assembly

Module Module1

Sub Main()
Dim assPath As String = "D:\Work\test\maindll\maindll\bin\Release\"
Dim assFullName As String

Try
Console.WriteLine("Starting...")

assFullName = assPath & "dllA.dll"
'assFullName = assPath & "dllB.dll"

launchDll(assFullName)

'Error return
'Non-static method requires a target.
'at System.Reflection.RuntimeMethodInfo.CheckConsistency(Object
target)
'at System.Reflection.RuntimeMethodInfo.Invoke(Object obj,
BindingFlags invoke
'Attr, Binder binder, Object[] parameters, CultureInfo culture,
Boolean skipVisib
'ilityChecks)
'at System.Reflection.RuntimeMethodInfo.Invoke(Object obj,
BindingFlags invoke
'Attr, Binder binder, Object[] parameters, CultureInfo culture)
'at maindll.Module1.launchDll(String thisDLL) in
D:\Work\test\maindll\maindll\
'Module1.vb() : line(84)

Console.Read()

Catch ex As Exception
Console.WriteLine(ex.Message & vbNewLine & ex.StackTrace)
Console.Read()
Finally

End Try
End Sub


Sub launchDll(ByVal thisDLL As String)

Dim ass As Assembly
Dim t, typ As Type
Dim m As MethodInfo
Dim p As ParameterInfo
Dim o As New Object
Dim ret As New Object
Dim obj As Object

Try
Console.WriteLine("Starting...")

obj = New Object() {"Nicolas"}

ass = Assembly.LoadFrom(thisDLL)
Console.WriteLine(ass.GetName.Name)


Console.WriteLine("Types:")
For Each t In ass.GetTypes
Console.WriteLine(t.Namespace & " : " & t.Name & " = " &
t.IsInterface)
If t.IsInterface Then
typ = t
o = ass.CreateInstance(t.Name)
Exit For
End If
Next

Console.WriteLine("Methods:")
For Each m In typ.GetMethods
Console.WriteLine(m.Name)
Next

m = typ.GetMethod("doThat")

Console.WriteLine("Parameters:")
For Each p In m.GetParameters
Console.WriteLine(p.Name)
Next



ret = m.Invoke(o, BindingFlags.CreateInstance Or
BindingFlags.Public Or BindingFlags.InvokeMethod Or BindingFlags.Default Or
BindingFlags.Static, Nothing, obj, Nothing)
Console.WriteLine(ret)

Console.Read()

Catch ex As Exception
Console.WriteLine(ex.Message & vbNewLine & ex.StackTrace)
Console.Read()

Finally
ass = Nothing
t = Nothing
typ = Nothing
m = Nothing
p = Nothing
o = Nothing
obj = Nothing
ret = Nothing

End Try
End Sub
End Module

--------------------------------------------------------------------------------

Namespace NA
Public Interface iA
Sub doThis(ByVal a As String)
Function doThat(ByVal a As String) As String
End Interface

Public Class cA
Implements iA

Sub New(ByVal myParam As String)
'..... do something
End Sub

Private Sub doThis(ByVal a As String) Implements iA.doThis
'do something with a
Console.WriteLine("A) " & a)
End Sub

Private Function doThat(ByVal a As String) As String Implements
iA.doThat
'do something with a
Return "A) " & a & " " & Now.ToString
End Function
End Class
End Namespace

--------------------------------------------------------------------------------

Namespace NB
Public Interface iB
Sub doThis(ByVal b As String)
Function doThat(ByVal b As String) As String
End Interface

Public Class cB
Implements iB

Sub New(ByVal myParam As String)
'..... do something
End Sub

Private Sub doThis(ByVal b As String) Implements iB.doThis
'do something with b
Console.WriteLine("b) " & b)
End Sub

Private Function doThat(ByVal b As String) As String Implements
iB.doThat
'do something with a
Return "B) " & b & " " & Now.ToString
End Function
End Class
End Namespace

--------------------------------------------------------------------------------
 
Nicolas said:
For Each t In ass.GetTypes
Console.WriteLine(t.Namespace & " : " & t.Name & " = " &
t.IsInterface)
If t.IsInterface Then
typ = t
o = ass.CreateInstance(t.Name)
Exit For
End If
Next

It seems you are trying to create an instance of a an interface type.
This does not work. You can only create an instance of a createable
class, for example class cA or class cB.

First change this, then we'll see which steps to take next.
 
Interface iA and IB are duplicates both cA and CB should IMO implement the
same interface.

It would be more something such as :

Dim o As iA

For Each t In ass.GetTypes
' This type implement this interface
If Not t.GetInterface("iA") Is Nothing
' So create the intance
o = CType(ass.CreateInstance(t.Name),iA)
Exit For
End If
Next

' Used directly through the common interface rather than by using Reflection

o.DoThat("Hello")
 
I try by pointing to the Class "cA" but does set/create the instance
regardless.

obj = New Object() {"Nicolas"}

For Each t In ass.GetTypes
Console.WriteLine(t.Namespace & " : " & t.Name)
If t.Name.ToLower = "cA".ToLower Then
'o = ass.CreateInstance(t.Name,True,0,Nothing,obj,Nothing,Nohting)
o = ass.CreateInstance(t.Name,True)
Console.WriteLine(isNothing(0).ToString) 'Return True
Exit For
End If
Next
 
I also try to create a common interface "dllInterface" which I then used in
each class dllA, dllB by inheriting from dllInterface.

in the application I set a reference to this common dll like:
dim o as dllInterface
and then try to create the instance of the class "cA" like
o = ass.createinstance("cA")
No luck here, o is nothing as well
 
Nicolas said:
I try by pointing to the Class "cA" but does set/create the instance
regardless.

obj = New Object() {"Nicolas"}

For Each t In ass.GetTypes
Console.WriteLine(t.Namespace & " : " & t.Name)
If t.Name.ToLower = "cA".ToLower Then
'o = ass.CreateInstance(t.Name,True,0,Nothing,obj,Nothing,Nohting)
o = ass.CreateInstance(t.Name,True)
Console.WriteLine(isNothing(0).ToString) 'Return True

Is this a zero that you pass to the isNothing function? First, it
doesn't make sense. Second, use "Is Nothing" if you wanted to compare a
reference with Nothing. Third, if it's "0", it always returns False
because it's a value type.

If it's just a typo in your posting (I think so because isNothing starts
with a lower case letter):
Instead of specifying the name (t.name) that will internally be used for
finding the Type, which is not necessary because your variable t already
points to it, you can directly call

Activator.CreateInstance(Type, ParamArray Object()) 'Signature!

The 2nd parameter is required because the class has only one constructor
with one parameter.
 
Moving ahead but now I got a constructor error not found?
No idea what it is since we are passing arguments.

******** CODE ************
obj = New Object() {"Nicolas"}
Dim o as New Object

ass = Assembly.LoadFrom(thisDLL)
Console.WriteLine(ass.GetName.Name)

Console.WriteLine("Types:")
For Each t In ass.GetTypes
Console.WriteLine(t.Namespace & " : " & t.Name) ' & " = " &
t.IsInterface)
If t.Name.ToLower = "cA".ToLower Then
o = Activator.CreateInstance(t, obj)
Console.WriteLine(o Is Nothing)
Exit For
End If
Next

******** CONSOLE *********
Starting...
dllA
Types:
dllA.My : MyApplication
dllA.My : MyComputer
dllA.My : MyProject
dllA.My : MyWebServices
dllA.My : ThreadSafeObjectProvider`1
dllA.NA : iA
dllA.NA : cA
Constructor on type 'dllA.NA.cA' not found.
at System.RuntimeType.CreateInstanceImpl(BindingFlags bindingAttr, Binder
bin
der, Object[] args, CultureInfo culture, Object[] activationAttributes)
at System.Activator.CreateInstance(Type type, BindingFlags bindingAttr,
Binde
r binder, Object[] args, CultureInfo culture, Object[] activationAttributes)
at System.Activator.CreateInstance(Type type, Object[] args)
at maindll.Module1.launchDll(String thisDLL) in
D:\Work\test\maindll\maindll\
Module1.vb:line 69
 
Nicolas said:
Moving ahead but now I got a constructor error not found?
No idea what it is since we are passing arguments.

******** CODE ************
obj = New Object() {"Nicolas"}
Dim o as New Object

ass = Assembly.LoadFrom(thisDLL)
Console.WriteLine(ass.GetName.Name)

Console.WriteLine("Types:")
For Each t In ass.GetTypes
Console.WriteLine(t.Namespace & " : " & t.Name) ' & " = " &
t.IsInterface)
If t.Name.ToLower = "cA".ToLower Then
o = Activator.CreateInstance(t, obj)
Console.WriteLine(o Is Nothing)
Exit For
End If
Next


I've tried it like you did but it works here. I assume you didn't change
class cA meanwhile.


Armin
 
You don't inherit from the interface you implement it. It would give
something such as the following code. Note that :

- the interface could be in its own file (others would need this to
implement your interface, I would avoid the parameterized constructor if
possible as it can't be included as part of the interface and so the
developer won't discover it should be implemented)

- the same o object can be used to directly call one or the other class
without using reflection. You'll get the same benefit if A or B instances
are created using Activator.CreateInstance.

- I would suggest to keep it simple and start to elaborate over there. For
now it is difficult to see if you have problems with the overall principle
or specific details (for example doe s it work when you use a non
parametized constrructor or is this the onyl problem left ?)...

Option Infer On
Public Module Module1
Interface ITest
Sub DoThis(ByVal arg As String)
End Interface
Class A
Implements ITest

Public Sub DoThis(ByVal arg As String) Implements ITest.DoThis
MsgBox("Class A")
End Sub
End Class
Class B
Implements ITest
Public Sub DoThis(ByVal arg As String) Implements ITest.DoThis
MsgBox("Class B")
End Sub
End Class

Sub Main()
Dim o As ITest
o = New A
o.DoThis("A")
o = New B
o.DoThis("B")
End Sub
End Module
 
Nicolas said:
No I did not change dllA and his class cA and I still get the constructor error

I'm afraid, I can't help then.

The only difference to my project was that I've put everything into one
assembly, but that shouldn't make a difference in this case. Despite,
now I've split it into 2 dlls and a console application, just like you.
Though, I do not get an exception.
 
Hi Patrice,
The setup you explain is not the one that I'm trying to achieve. because in
this case I will always have to set reference to classes or have the classe
within this module.
The idea that I'm looking for is as follow

Have a Main application which will server different module based on customer
needs
MainAPI (distributed to customer)

Now I got Modules (dlls) which could be used by the MainAPI,
Customer 1 would like to have Module 1 (dllA) and Module 2 (dllB)
Customer 2 would like to have Module 1 (dllA) and Module 3 (ddlC)
Customer 3 would like to have Module 3 (dllC)
and so on

Each module woould have the same structure and public sub Like for example
Public Function GiveMePrice(myParam as string) as String

In Module 1 GiveMePrice return price of the Car myParam
In Module 2 GiveMePrice return price of the StockMarket for myParam
In Module 3 GiveMePrice return Salary of employee myParam

So the list of module could expand and I don't want to recompile MainAPI all
the time and send customer with all modules since they dont need them all.
Upon request I'll send the required modules.


A bit of a long text but it may explain more in details what I'm trying to
achieve here.
Thanks
 
Lucky you :)
May be you could send me by email your code so I can try here. Because here
I'm still trying and going no where.
(e-mail address removed)

Thanks a lot for your help
 
The setup you explain is not the one that I'm trying to achieve. because
in
this case I will always have to set reference to classes or have the
classe
within this module.

I understood. As I said you'll have the same benefit if using CreateInstance
(and loeading whatever DLL my fit). My point is that in your original code :
- you define multiple times interfaces with the same method and each class
implements its own unique interface
- you were calling the methiod using reflection

Instead :
- you can define the unique interface you need and have all classes
implement this interface
- then you can call the method without using reflection.

You don't inherit. The main point of my post was to show the Implements
keyword not the all mechanism that you seems to have right (expect for the
constructor call)...
 
Nicolas said:
Lucky you :)
May be you could send me by email your code so I can try here. Because here
I'm still trying and going no where.
(e-mail address removed)

Well, it's the code I got from you.
 
Back
Top