How to call a sub routine of one form from other form? - vb.net

i'm a new in vb.net, i would like to ask if how can I call a sub routine of the main form from another form.
I tried putting the prefix of the main form( main.subroutinename() ), it doesn't show an error when compiled but it doesn't work either.

As Microsoft says:
Calling syntax
You invoke a Sub procedure explicitly with a stand-alone calling statement. You cannot call it by using its name in an expression. You must provide values for all arguments that are not optional, and you must enclose the argument list in parentheses. If no arguments are supplied, you can optionally omit the parentheses. The use of the Call keyword is optional but not recommended.
The syntax for a call to a Sub procedure is as follows:
[Call] SubName[(argumentlist)]
You can call a Sub method from outside the class that defines it. First, you have to use the New keyword to create an instance of the class, or call a method that returns an instance of the class. For more information, see New Operator. Then, you can use the following syntax to call the Sub method on the instance object:
Or you can create a Sub Routine in a Module making it visible (Friend or Public, etc) then calling it inside entire the Namespace that contain your Module
object.MethodName[(argumentList)]
Illustration of declaration and call
The following Sub procedure tells the computer operator which task the application is about to perform, and also displays a time stamp. Instead of duplicating this code at the start of every task, the application just calls tellOperator from various locations. Each call passes a string in the task argument that identifies the task being started.
Sub tellOperator(ByVal task As String)
Dim stamp As Date
stamp = TimeOfDay()
MsgBox("Starting " & task & " at " & CStr(stamp))
End Sub
The following example shows a typical call to tellOperator.
tellOperator("file update")

Related

Calling Macro from inside Macro - Error Compile Error: Expected variable or procedure, not module - Private Sub App [duplicate]

This question already has answers here:
What does the Call keyword do in VB6?
(5 answers)
Closed 3 years ago.
I have been copying code moslty to work on and learn macro's in Word. I have got it working where I can get a MsgBox to appear before printing, but I would like it to call another module/macro to compartmentalize the modules.
For testing, this works:
Private Sub App_DocumentBeforePrint(ByVal Doc As Document, Cancel As Boolean)
MsgBox "Before Print"
End Sub
But if I do:
Private Sub App_DocumentBeforePrint(ByVal Doc As Document, Cancel As Boolean)
Call Greeting
End Sub
Which is a working macro that I have which simple opens a MsgBox and says "Greetings", I get the following error:
Compile Error: Expected variable or procedure, not module
How can I call another Macro inside this Private Sub App*?
While this post has been covered before, I will share the answer here as well in case others land here.
The issue is that you can't have a module named the same as a sub. See Screenshot below for what is WRONG!
Interestingly, if you put the sub that calls the other sub (greeting) inside the same module (greeting) it works! But I would say this is bad practice and should be avoided. See example below:
I will generally just append _Sub to my module names to avoid this issue like below:
Also a note about using the keyword Call.
You are not required to use the Call keyword when calling a procedure.
However, if you use the Call keyword to call a procedure that requires
arguments, argumentlist must be enclosed in parentheses. If you omit
the Call keyword, you also must omit the parentheses around
argumentlist. If you use either Call syntax to call any intrinsic or
user-defined function, the function's return value is discarded.
See here for more information --> What does the Call keyword do in VB6?

How can I run several macros where the Macro name begins with a specific string of characters?

I've created several custom functions which I would like to Register. Currently, I have a different procedure for which I specify the registration for each function (there's no issue with that piece). However, the only way I know of to registering all these functions is by calling each Macro by name in another procedure like this:
Sub spRegisterFunctions()
Call spRegisterCUSTOMAfunction
Call spRegisterCUSTOMBfunction
Call spRegisterCUSTOMCfunction
Call spRegisterCUSTOMDfunction
End Sub
I'm actually looking for something more dynamic so that every time I create a new function, and it's corresponding "spRegister..." procedure, I don't have to remember to add the "Call" code to the "Sub spRegisterFunction()" procedure for that specific function.
Here's an example of what attempting to do:
Sub spRegisterFunctions()
Dim mc as Macro
For Each mc in VBProject("NameOfProject").Module("NameOfModule")
If Left(mc.Name,10)="spRegister" then
Call mc
End If
Next mc
End Sub
As you can see, I'm attempting to run any macro in a specific module who's name begins with "spRegister". Obviously the code above will not work, partly because some of those objects don't even exist.
Is there any way to do this?

In Visual Basic .NET, how can I list and call all class functions with a given custom attribute?

I have a Windows Forms / Visual Basic .NET application which basically acts as an editor. One of the functions it should provide its users with is the ability to run a set of rules on their current project and report any problems it finds. These rules will all be run by a BackgroundWorker object living in a form, so execution progress can be reported.
My strategy for implementing this is to give the form a bunch of private instance methods which take in the user's project data (contained in, say, a ProjectData object), run whatever check is needed at that step, and return an object containing displayable information about the test and whether it passed or failed. (Let's call this class CheckResult for discussion purposes). So, just to be clear, all of these methods would have a signature along the lines of:
Private Function SomeCheckToRun(data As ProjectData) As CheckResult
I could just define all these methods as usual and manually list them out one-by-one to be called in the BackgroundWorker's DoWork event handler, but that approach seems like it would get tedious for a potentially large number of checks. It would be nice if I could just define each method I want to run and have it decorated as such, so that a loop could automatically find each such method definition and run it.
What I'm thinking I would like to do instead is to define a custom attribute class used to indicate which instance methods are meant to be run as checks (maybe called CheckToRunAttribute), then use reflection somehow to get a list of all these methods currently implemented in the form and execute each one in sequence, perhaps by setting up a delegate to run for each one. The number of these methods in total, and how many have been executed so far, can be used by the BackgroundWorker to indicate overall progress.
So far, the structure of my code would look something like the following in my mind:
Private Sub MyBackgroundWorker_DoWork(sender As Object, e As DoWorkEventArgs) Handles MyBackgroundWorker.DoWork
' TODO: Get a list of all the <CheckToRun()> methods here,
' run each one in a loop, and report progress after each one.
End Sub
' Further down...
<CheckToRun()>
Private Function SomeCheckToRun(data As ProjectData) As CheckResult
' Check code in here.
End Function
<CheckToRun()>
Private Function AnotherCheckToRun(data As ProjectData) As CheckResult
' Check code in here.
End Function
<CheckToRun()>
Private Function YetAnotherCheckToRun(data As ProjectData) As CheckResult
' Check code in here.
End Function
' And so on...
This is not something I have much experience with doing though. I know about the Type.GetMethods() function, how to write custom attributes, and the Func(T, TResult) delegate, but I'm not sure how to put it all together for what I want.
tl;dr: Given a class with multiple private instance functions following the same signature and all marked with the same custom attribute, how can I count how many there are and then run each one?
You can use Reflection to list all the methods with your custom attribute. This is a Linq solution:
Dim methods = Me.GetType.GetMethods(Reflection.BindingFlags.NonPublic Or Reflection.BindingFlags.Instance)_
.Where(Function(m) m.GetCustomAttributes(GetType(CheckToRun), False)_
.Length > 0).ToArray()
And then run them like:
For Each method As Reflection.MethodInfo In methods
method.Invoke(Me, New Object() {methodParams})
Next

A function that works in Vb.net a class, but not in a module

Writing in VS2012 using VB.Net, I am using a table of functions to interpret a script file.
The script file consists of lines like this:
#keyword,(string)
All the functions, and the dictionary, live in a module. All the functions have the same signature, so I can use them as delegates.
In a form, I read the script file and then process each line, extracting the keyword and the string accompanying it. Using the keyword, I get the address of the function I want from the dictionary, then call this function, passing it the string as a parameter. I use this syntax:
fndic(keyword)(string)
This works fine, finding the right function and executing it properly, except...
One of the functions puts text on a label:
Public Function fhdr(s As String) As Boolean
Form1.Header.Text = s
End Function
Only it doesn't. So to see if it works, I put in an extra line:
Public Function fhdr(s As String) As Boolean
MessageBox.Show("hdr " + Form1.Header.Text + " new " + s)
Form1.Header.Text = s
End Function
The message box appears, but the text still doesn't. So I put this function in the class of the form, and now it works!
So my question is – why does the function alter the form when it's in the form's code, but not when it's in the module?
Is there some arcane statement I must put in the module to make it aware of the form? Or should I just dump all the code into the form, making a big unlovely stew with 40 functions in it?

Reference to a non-shared member requires an object reference in VB.net

I have a VB.net program that I got from someone else. It is comprised of a main form and 6 other modules (all .vb files). These files all have a "VB" icon next to them in the Explorer pane. I am trying to make a call to a sub-routine in one of the modules from the main form. My line of code is:
QuoteMgr.StartGettingQuotesLevel2(sSym)
where QuoteMgr is the name of the module and StartGettingQuotesLevel2(sSym) is the name of the sub-routine. When I enter this, I get the error message:
Reference to a non-shared member requires an object reference.
The sub-routine is defined in the QuoteMgr Module as follows:
Public Sub StartGettingQuotesLevel2(ByVal oSymbol As String)
What is strange is when I enter:
QuoteMgr.
(the name of the module with a period), it does not show me all the sub-routines and functions in the module. It only shows:
Update_Level1
Update_Level12
Update_Level2
These are Public Const in the module.
Can you tell me what I need to do?
What the compiler is trying to tell you with this error message
Reference to a non-shared member requires an object reference
is that the StartGettingQuotesLevel2 subroutine is an instance method not a shared or class method, see a more detailed explanation here
To call an instance method, you need to have an object instance to call it on. In your case, an object instance of the class type QuoteMgr. Like in the example below:
' create a new QuoteMgr object instance
Dim myQuoteMgr As QuoteMgr = New QuoteMgr()
' call its instance method with "abc" as its oSymbol argument.
myQuoteMgr.StartGettingQuotesLevel2("abc")
It is possible that you only want a single QuoteMgr object instance to be created and used by your main form. In that case, you can make it a member variable of your main form and create it once.
Public Partial Class MainForm
' Create it as a private member variable of the main form
Private m_QuoteMgr As QuoteMgr = New QuoteMgr()
' Use it when "some" button is pressed
Private Sub btnSome_Click(sender As Object, e As EventArgs) Handles btnSome.Click
m_QuoteMgr.StartGettingQuotesLevel2(txtSymbol.Text)
' And possibly do something with the results.
End Sub
End Class
Also, if instances of your QuoteMgr class depend on other object instances for their tasks, you will have to supply these to the constructor method of the QuoteMgr class as the arguments for its constructor's method parameters. Constructors (Sub New(...)) look like this:
Public Class QuoteMgr
' This is a constructor that takes two arguments
' - oMainSymbol: a string value
' - oKernel: an instance of the type Kernel
Public Sub New(oMainSymbol As String, ByRef oKernel As Kernel)
' ....
End Sub
End Class
That means, that when you create a QuoteMgr instance, you have to call its constructor method with the things it need, for example
' There must be an instance of Kernel created somewhere.
Dim myKernel As Kernel = ....
' create a new QuoteMgr object instance with these arguments:
' - oMainSymbol = "SYMABC"
' - oKernel = myKernel
Dim myQuoteMgr As QuoteMgr = New QuoteMgr("SYMABC", myKernel)
Some other recommendations
The explanations I have provided, are about basic VB.NET language features (e.g. the terms highlighted in bold). I suggest that before you make any changes to the code you have, you (1) make a backup of it, and (2) try to read a tutorial and practice on something smaller.
The compiler is (virtually) always right. When it gives you an error message, read it carefully, it will indicate the line where something is wrong and a message that tells you what it needs or is missing.
It is not the purpose of Stack Overflow to provide tutorials or code. It is a Q&A site where the best questions and answers deal with specific, delineated programming problems, for which succinct answers are possible.
Right click your application and go to Properties.
Make sure your application type is "Windows Forms Application".
It means that the routine you are trying to call needs to reference an instance of the form to access the routine. You can either reference an instance as Alex says, or you can make the routine 'Shared', so it doesn't need an instance. To do this, change the definition in QuoteMgr.vb to
Friend Shared Sub StartGettingQuotesLevel2(ByVal oSymbol As String)
Switching it to `Shared' may start showing compiler errors, if the routine accesses form controls or module-level variables. These will need to be added to the parameter list.