VB.NET Plugin Architecture - vb.net

Hello I'm working on using the interface class in vb.net to make a plugin architecture. So far I've not found a step by step tutorial for a beginner. But I've gotten as far as this:
Main App
Public Class PluginHandler
Interface IApplications
Sub ChangeForms()
End Interface
Public Shared Sub GetDLLFromDir(ByVal TheDir)
For Each dll As String In System.IO.Directory.GetFiles(TheDir, "*.dll")
LoadPlugin(dll)
Next
End Sub
Public Shared Sub LoadPlugin(ByVal ThePlugin)
Dim Asm = Assembly.LoadFile(ThePlugin)
Dim type As Type = Asm.GetType("TestPlugin.Class_TestPlugin")
Dim method As MethodInfo = type.GetMethod("ChangeForms")
method.Invoke(Nothing, Nothing)
End Sub
End Class
TestPlugin.vb
Public Class Class_TestPlugin
Implements Plugin_Application.PluginHandler.IApplications
Sub ChangeForms() Implements Plugin_Application. _
PluginHandler.IApplications.ChangeForms
Dim NewForm As New Form_Test
NewForm.Show()
End Sub
End Class
My issue is it says for the method to invoke --> Non-static method requires a target.
I seen on another forum that the method may not be found. I found it says the methods name and void. But I'm not sure what to do. If somebody can mod my code to work or give me some ideas to make my code work. Thanks :)
Here is a link to my test project folder: Link

You have to create an object the method should be called on:
Dim ctor = type.GetConstructor({}) 'no parameters for constructor
Dim obj = ctor.Invoke({})
method.Invoke(obj, {})

Related

How to get access to the functions from a module

I need to get access to the public functions in a module (not a class). This is what I have tried:
Dim asm As Reflection.Assembly = Assembly.GetExecutingAssembly
Dim my_modules = asm.GetModules
For Each my_module In my_modules
Dim all_methods = my_module.GetMethods
Stop
Next
But that doesn't even get down to the module itself, I just get the name of the executable.
As #jmcilhinney said in the comments a Module is like a Class when using reflection. You can access it using GetType or GetTypes method.
Dim asm As Assembly = Assembly.GetExecutingAssembly
Dim my_module = asm.GetType("Module_Full_Name")
Dim allMethods = my_module.GetMethods()
Module in VB.NET is nothing else than static class. You not create instance of static class, just call its members from anywhere in scope where module is declared.
Public Module Mathematics
Public Function Sum(x As Integer, y As Integer) As Integer
Return x + y
End Function
End Module
Class Form1
Public Sub New()
InitializeComponent()
Dim result = Mathematics.Sum(1, 2)
End Sub
End Class

How to apply threading in vb.net with passing an object of a custom class for a method

I am newbie here. I need your help. I am trying to develop a tool where I want to implement multi-threading in vb.net. I am stuck in a place which I could not resolve. Let me explain you.
I have created a custom class as below:
Public Class TestClass
'Few private Members of my class
Private a As String,b As String
Public Structure abc
Dim xx as object
Dim yy as object
Dim zz as object
End Structure
Public aa(10) As abc
'Now I needed to override the constructor as the initialization of
'instance of this class can be made in two different ways due to
'requirement
Public Sub New(ByVal xy As String,ByRef yz As Object)
'Some internal method to initialize the object
Me.a=xy
Me.b=xy
End Sub
'Another way to create the instance
Public Sub New(ByVal xy As String,ByVal yz As String)
'Some internal method to initialize the object
Me.a=xy
Me.b=yz
End Sub
'Now a public method which I want to call using threading
Public Sub TestSub()
'Do something with Me.a,Me.b and aa(some index)
End Sub
End Class
Now in a different module I am creating the instance of this class as below:
Dim X1 As New TestClass("Some String",<Some Object reference>)
Dim X2 As New TestClass("Some String","Some String")
Now I have declared a sub in the same module like below
Sub DoMyStuff(ByRef A1 As TestClass)
A1.TestSub()
End Sub
After all This I want to create a thread and run the sub "DoMyStuff" by Passing a reference of X1
To Do this I have Imported System Threading:
Imports System.Threading
Inside Module after initialization of X1 and X2 I have written:
Dim T1 as New Threading.Thread(AddressOf DoMyStuff)
T1.Start(X1)
Here I am getting error: Overload Resolution Failed because no 'New' can be called with this arguments: 'Public Sub New(Start As System.Threading.ParameterizedThreadStart, maxStackSize As Integer)': Method 'Public Sub DoMyStuff(ByRef A1 As TestClass)' does not have a signature compatible with delegate 'Delegate Sub ParameterizedThreadStart(obj As Object)'. 'Public Sub New(Start As System.Threading.ThreadStart, maxStackSize As Integer)': Method 'Public Sub DoMyStuff(ByRef A1 As TestClass)' does not have a signature compatible with delegate 'Delegate Sub ThreadStart()'.
If I am writing like this,
Dim T1 As Threading.Thread
T1 = (AddressOf DoMyStuff)
T1.Start(X1)
I am getting the error: 'AddressOf' expression can not be converted to 'System.Threading.Thread' because 'System.Threading.Thread' is not a delegate type.
Might be I am missing some thing, which I am unable to find. I am not so much good in Delegate type concept. Also this is my first project with implementation of Threading. Looked for answers in Google but unable to understand to sort out. Your help highly solicited.
Thanks
Edit:
I have checked your reference Michael Z. and its really helpful. First of all a big Thank you for that :)
However, I am unable to understand a thing in there. If you help me out there, I would be highly grateful. As per my understanding, I have changed my code as below:
Public Delegate Sub Test2(ByRef A1 as TestClass)
Public T1 as Test2 = New Test2(AddressOf DoMyStuff)
Public Sub DoMyStuff(ByRef A1 as TestClass)
A1.TestSub()
End Sub
Now I have Declared in my module as follows:
Dim T as Threading.Thread = New Threading.Thread(AddressOf DoStuff)
Here I am unable to understand how to write the DoStuff sub as in your example you were working with TextBox1 which is an object in UI, so you wrote:
Public Sub DoStuff()
If TextBox1.InvokeRequired Then
TextBox1.Invoke(T1,"Hello")
End If
End Sub
But here I need to work with an object which is custom made i.e. X1 or X2. Also I need to pass the reference of the object in the Thread so that the method TestSub can work with the created object either X1 or X2. Totally lost here :(
Please correct me if anywhere I am wrong to understand your reference, otherwise if correctly understood, can you Please help me out here. Appreciate your help in advance.
Thanks
Firstly, ensure you're calling this from a method:
Dim T1 as New Threading.Thread(AddressOf DoMyStuff)
T1.Start(X1)
Next remove the ByRef in the method parameter like so Sub DoMyStuff(A1 As TestClass)
Essentially make your second Module look like:
Module Module2
Dim X1 As New TestClass("Some String", "asd")
Dim X2 As New TestClass("Some String", "Some String")
Sub TestCall
Dim T1 as New Thread(AddressOf DoMyStuff)
T1.Start(X1)
End Sub
Private Sub DoMyStuff(A1 As TestClass)
A1.TestSub()
End Sub
End Module
And you can call it like so:
TestCall()
Try using a simple Call method;
Call New Threading.Thread(AddressOf DoMyStuff).Start(X1)
Looking at what you wanting, there seems no reason to assign this to a variable?
Also - remember, when working with multiple contructors, you need to ensure the [TYPES] you pass in are correct and expected (this could be why your current process isn't working).
See this link for a similar issue.

Bootstrapper class not found in Nito.AsyncEx

Please see the answer to the following question: Can't specify the 'async' modifier on the 'Main' method of a console app
I am trying to do this with a VB.NET program. I have added the package using NUGET and I have ensured that the Reference is added. Please see the code below:
Imports Nito.AsyncEx
Public Class ScheduledTasks
Private Shared Async Sub MainAsync(args As String())
Dim bs As New Bootstrapper()
Dim list As VariantType = Await bs.GetList()
End Sub
End Class
The error is: Type BootStrapper is not found. I have used Intellisense to look at the types contained in Nito.AsyncEx and Bootstapper is not there? How do I create an asynchronous main method using VB.NET?
Bootstrapper is not a part of AsyncEx. AsyncContext is:
Imports Nito.AsyncEx
Public Class Program
Private Shared Sub Main(args As String())
AsyncContext.Run(Function() MainAsync(args))
End Sub
Private Shared Function MainAsync(args As String()) As Task
...
End Function
End Class

Vb.Net Class file on load sub?

I hope this isn't a stupid question, I can't find a reasonable answer on google.
I'm starting a project which only contains one class file. I will be turning the class file into a dll at the end. I understand that another app normally makes calls to the dll once it's referenced in the project. I need the dll to run a sub inside of it on load like a normal mybase.load sub. This sub needs to execute only once on load to populate some variables. I don't want to have to call the sub from the main app. The rest of the functions/subs in the dll will be called from the main app when needed. Please don't respond with register them globally under the class, I need a sub or function.
If there isn't such a sub how would I go about creating a function/sub that preforms an onload?
Thanks. :)
Hope I'm making sense. Thanks for your response.
Shared Sub New()
on your class.
Another option is to have a private class inside your class and initialise it with a member variable:
Public Class MyLibraryClass
Private mobjSettings As New SettingsClass
Public Function SampleLibraryFunction() As String
Return mobjSettings.SettingsProperty
End Function
Private Class SettingsClass
Friend SettingsProperty As String
Sub New()
'initialise
SettingsProperty = "This is a test"
End Sub
End Class
End Class

.net dynamic loading

I've seen some other responses about this and they talk about interfaces but I'm pretty sure you can do this with classes and base classes but I can't this to work.
Public Class Behavior
Private _name As String
Public ReadOnly Property Name As String
Get
Return _name
End Get
End Property
Public Property EditorUpdate As Boolean
Public Sub New(ByVal name As String)
_name = name
EditorUpdate = False
End Sub
Public Overridable Sub Update()
End Sub
' runs right away in editor mode. also runs when in stand alone game mode right away
Public Overridable Sub Start()
End Sub
' runs after game mode is done and right before back in editor mode
Public Overridable Sub Finish()
End Sub
' runs right when put into game mode
Public Overridable Sub Initialize()
End Sub
' runs when the game is complete in stand alone mode to clean up
Public Overridable Sub Destroy()
End Sub
End Class
Public Class CharacterController
Inherits Behavior.Behavior
Public Sub New()
MyBase.New("Character Controller")
End Sub
Public Overrides Sub Update()
' TODO: call UpdateController()
' THINK: how can UpdateController() get the controller entity it's attached to?
' Behaviors need a way to get the entity they are attached to. Have that set when it's assigned in the ctor?
End Sub
End Class
Dim plugins() As String
Dim asm As Assembly
plugins = Directory.GetFileSystemEntries(Path.Combine(Application.StartupPath, "Plugins"), "*.dll")
For i As Integer = 0 To plugins.Length - 1
asm = Assembly.LoadFrom(plugins(i))
For Each t As Type In asm.GetTypes
If t.IsPublic Then
If t.BaseType.Name = "Behavior" Then
behaviorTypes.Add(t.Name, t)
Dim b As Behavior.Behavior
b = CType(Activator.CreateInstance(t), Behavior.Behavior)
'Dim o As Object = Activator.CreateInstance(t)
End If
End If
Next
Next
When it tries to convert whatever Activator.CreateInstance(t) returns to the base class of type Behavior I'm getting invalid cast exception. That type should be of CharacterController which is defined as a child of Behavior so why wouldn't it let me cast that? I've done something like this before but I can't find my code. What am I missing?
This may not be an answer to your question (it also might resolve your exception -- who knows), but it is something that needs to be pointed out. These lines:
If t.IsPublic Then
If t.BaseType.Name = "Behavior" Then
Should really be changed to one conditional like this one:
If t.IsPublic AndAlso (Not t.IsAbstract) AndAlso _
GetType(Behavior.Behavior).IsAssignableFrom(t) Then
Otherwise, if somebody defines a random type called "Behavior" in their own assembly and derives it from another type, your code will think it is a plugin. Additionally, if someone derives your Behavior type and then derives that type (two levels of inheritance) this code will incorrectly skip over that type. Using the IsAssignableFrom method is a quick and easy way to ensure that one type does actually derive from the specific type you want (instead of any type that shares the same name), even if there is another type in between your types in the inheritance tree. The additional check against t.IsAbstract will also ensure that you don't try to instantiate an abstract subtype of your base plugin type.
This works for me:
Dim ctor As Reflection.ConstructorInfo = _
t.GetConstructor(New System.Type() {})
Dim o As Object = ctor.Invoke(New Object() {})
Dim plugin As Plugin = TryCast(o, Plugin)
(If I find t, I invoke the parameterless constructor.)
[I just realized this is probably what Activator.CreateInstance does, so I replaced my code with yours and it worked your way -- so this probably won't help you]