VB.Net App Stuck in Loop - vb.net

I would just like the program to end itself.
Application.Exit just keeps rolling me back in a loop.
EDITED to Include Code::
Module Module 1
Sub Main()
Sub1()
Sub2()
End Sub
Sub1()
EndSub
Sub2()
End Sub
End Module
EDIT: It seems to be looping back here to Sub ChooseDomain2.. I am including Sub 1 as well.
Sub ChooseDomain1()
Dim DomainName As Object
'Get List of all users on Domain using WinNT
DomainName = InputBox(messageOK, Title, defaultValue)
de.Path = "WinNT://****".Replace("****", DomainName)
If DomainName Is "" Then ChooseDomain2() Else StoreUserData1()
End Sub
Sub ChooseDomain2()
MsgBox("Welcome to the Domain Searcher. Click OK to Auto Search for Domain")
Dim MsgBoxResult As Object = ActiveDirectory.Domain.GetCurrentDomain.Name
MsgBoxResult = InputBox(messageCan, Title, MsgBoxResult)
de.Path = "WinNT://*****".Replace("*****", MsgBoxResult)
StoreUserData1()
End Sub

When it hits end Module it Just starts back from Square one.
Modules don’t execute at all – so it never “hits end module” and never starts “from square one”. Modules merely group methods that can be executed, and Main is a special method that serves as the start of your application.
That said, your code is guaranteed (!) not to execute repeatedly. Also, there is no Application.Exit anywhere in your code so it’s hard to see what you are actually executing. Not the code you showed, anyway.
Note that VB potentially executes code that you didn’t write (code can be auto-generated by the compiler, in particular the application framework) but this doesn’t seem to be happening in your case, and shouldn’t loop in any case. But again, this is impossible to say from the information you have given.

Application.Exit is not required as the console app will quit after it finishes executing the last line in Sub Main. As previously mentioned it is likely you have Sub1 calling Sub2 (or something similar), so set a breakpoint on the start of each sub to find which one is continually being called. Then you can do a search in your code to find where this sub is being called from.

Related

How to end one procedure (Sub, Function) from another in VB.net?

I want to end a main sub from another sub.
Here is an example code to illustrate what I need to do:
Sub main()
endMainSub()
'do other stuff
End Sub
Sub endMainSub()
**'here I need a code to end main Sub**
End Sub
From endMainSub, I would like to terminate main sub before "do other stuff".
I need something like "End" in VBA.
End exists in VB.NET too, so you could use it. You should NEVER do so though. End simply stops executing the application at that point, with no regard for what state it might be in. It's like closing applications by using End Task in Task Manager, which I hope you use only as a last resort.
As suggested, you should be returning a result from the second method that indicates that the application should exit and the first method should explicitly choose to exit or not based on that, e.g.
Sub Main()
If EndMainSub() Then
Return
End If
'...
End Sub
Function EndMainSub() As Boolean
Dim result As Boolean
'Some work that sets result here.
Return result
End Function
I think you should use
Application.Exit
It's more object orientated and allows to execute all closing and disposing events. "End" still exists, but it will end immediately and no clean up routines will be executed.

VBA Excel Call and Run breaking backtracking

I'm making a workbook with a whole lot of different subs, and in an effort to avoid a user accidentally activating a sub that erases the code of a sheet for example, I've tried making all the subs private instead.
My subs can now only be activated by clicking buttons on the worksheet, and it all works as intended. Untill a sub of mine tries to call a private sub in another module of course.
To get around this I used Application.Run rather than Call, which worked and also allows me to call in a variable "NextSub" from the previous sub, which gives me some flexibility that I need, and apparently cant get with the Call.
Eg.
Sub FirstSub()
*Something going on
Application.Run "SecondSub", SomeVariableSub
End sub
Sub SecondSub(Nextsub as String)
If something Then
*Do something
Application.Run NextSub
Else
Application.Run NextSub
I thought that the Application.Run had solved all my problems, but I used to have a line that called an errorhandler, which in turn called a sub. It seems that the program can no longer backtrack to the sub that contained the errorhandler as it could when I used Call.
Does Applciation.Run break this functionality? If yes, can I then use Call with a variable NextSub as I am doing it now? And if I can't use the Call that way, then is all this fixed by adding a On Error GoTo ErrorHandler in the affected subs?
I know that the whole thing about calling Private Subs across modules is probably pretty bad practice, but I was compltely new to this when I started out, and the project is too extensive to fix that without rewriting all of the code.
Instead of making all subs private, either put Option Private Module on top of each module, or add a dummy argument to each routine:
Sub SomeHiddenRoutine(bDummy As Boolean = False)
'Routine can be called as usual using:
SomeHiddenRoutine
End Sub
If I understand you are trying to call a function specified by a string.
The correct way is to use something like this, which allows you to call all the private subs (as long as it is in the same module as the private functions):
Sub CallFunction(FuncName As String)
Select Case FuncName
Case "Func1": Func1
Case "Func2": Func2
Case "Func3": Func3
End Select
End Sub

Visual Basic Console - A global command & anwser string

I'm creating a text based adventure game and would like to create some "global" commands & answers that would work anywhere no matter where your are.
For the global answers if we look at this code:
Module Module1
Private Property answer1 As String
Private Property answer2 As String
Sub Main()
Console.WriteLine("Welocome to the training grounds!")
Console.WriteLine("What would you like to do? 1. I would like to train on dummies")
answer1 = Console.ReadLine()
Console.WriteLine()
If answer1 = "1" Then
Console.WriteLine("Okay what now?")
answer2 = Console.ReadLine
If anwser2 = "1" Then Console.WriteLine("New option")
End If
End Sub
Now as you can see I have to create a string for each new user input. I've tried doing a Public answer As String = Console.ReadLineand then having things react to "answer" but if I reused a keyword like number 1 in the code up top the program would not wait for user input and just go down the path of number 1. The first option seems like a bunch of spagettih code and the second option dose not seem to work or I myself am not getting it to work so any tips here would be nice.
I also want to know if its possible to create a global string or something of sorts. Say that No matter if I were at the point where I'm supposed to give input to answer 1 or 2, if I typed in "inventory" it would open another sub called inventory. Now if possible I want to do this without having to have an if answer = inventory then Inventory().
Thanks in advance everyone ^^
Following the advice given to my by b.pell I was able to create a "GameCommand" sub but I'm not facing a problem of how to implement these into the game itself/make them accessible without ruining the game flow. I am also not quite sure how to write a command that will modify something in GameCommand.vb (say if the player gets an item how would I add it to the inventory list?)
Module Module1
Sub Main()
Dim gc As New GameCommand
If Console.ReadLine = "Go to dummy" Then Dummy() Else
CallByName(gc, Console.ReadLine, CallType.Method, "")
End Sub
Sub Dummy()
Console.WriteLine("I am dummy hear me roar")
Return
End Sub
End Module
The GameCommand.vb file is the same as the one in p.bells comment.
You could create an interpreter function that processes all commands and then do what you want in there. So everytime you read input in, just pass it along to the interpreter sub.
interpreter("inventory")
Inside of there, you could do an break that command up (if it has arguments). You could do a basic if statement and execute your sub procedures based off of that.
You could go above and beyond (this answers your question about not having to write the if's) and create a commands class that has all of your command methods on it (Inventory, North, South, East, West, Look) and then when a user enters a command you could use reflection to check that class to see if that sub/function exists (and then invoke it). The benefit of that is, as you add methods to the command class you never have to update the if logic in your interpreter again.
E.g. You would add a "Public Sub Look()" or "Public Sub Look(args as String) to the command class.. your interpreter would then try to invoke the look command (and maybe pass it the rest of the arguments). If it wasn't found, you tell the user it wasn't a command, if it was, it executes (google search for invoking). This means as you add Sub's the interpreter just picks them up.
Here is an MSDN article that should get you going, you can use VB's CallByName function, you pass it your class, then the proc name you want to execute with an args:
https://msdn.microsoft.com/en-us/library/chsc1tx6(v=vs.80).aspx
Here is a simple example (a console application):
Module1:
Module Module1
Sub Main()
Dim gc As New GameCommand
CallByName(gc, "Inventory", CallType.Method, "")
' Will look south
CallByName(gc, "Look", CallType.Method, "south")
' Will try to look southeast, but we don't accept that as a valid direction
CallByName(gc, "Look", CallType.Method, "southeast")
Console.ReadKey()
End Sub
End Module
GameCommand.vb:
Public Class GameCommand
Sub New()
End Sub
Public Shared Sub Inventory(arg As String)
Console.WriteLine("Execute code to show inventory")
End Sub
Public Shared Sub Look(direction As String)
If direction <> "north" And _
direction <> "south" And _
direction <> "east" And _
direction <> "west" Then
Console.WriteLine("Invalid direction")
Exit Sub
End If
Console.WriteLine("You look " & direction)
End Sub
End Class
I would approach a text adventure with the following general structure:
In your main module, loop through the process of each "turn".
Display any prompt text, as appropriate.
Read user input.
Check list of global commands and execute as appropriate.
Check list of local commands and execute as appropriate.
Display an error message.
Each command you execute should do the following:
Calculate changes to any variables affected by the command
Check each possible change in game status from the top down, and execute subsequent commands as appropriate. (E.G. Player death, mission success/failure, enemy defeated, etc.)
Advance the story to the appropriate place.

Optionally launch form in VB.Net console application

So I've set my application to a console type application and pointed it to a module containing just Sub Main, i.e.
Module mdlConsole
Sub Main(ByVal cmdArgs() As String)
If cmdArgs.Length = 0 Then
Dim frm As New frmMain
frm.Show()
End If
End Sub
End Module
Ideally if no arguments are supplied then the program would simply launch the primary form. The goal is to make this program (optionally) script-able from the command line. If arguments are supplied then the application form is not loaded and processes its features based off the command line arguments supplied.
As it is now, the program runs, briefly launches the form (frmMain) and then closes. What am I doing wrong or missing?
If you're not keen on giving me the answer, I'd be happy to be pointed in the right direction also. I don't expect anyone to just supply answers. I need to learn also.
Thanks!
For Winforms, you need to 'run' the App object, passing a form to use:
Sub Main(ByVal cmdArgs() As String)
If cmdArgs.Length = 0 Then
Dim frm As New frmMain
Application.Run(frm)
Else
' cmd line version
End If
End Sub
I see in your comment that you'd like to remove the console window that appears when running the form version of the program with the solution currently proposed. I cannot comment due to lack of reputation, so I will make this a full-fledged answer.
Consider approaching this from an inverse perspective: if you write the program as a forms application, opening it by default will bring up the form. But in the Form1_Load event, check the command line arguments; if they are greater than 0, simply run your (abbreviated) code logic here. At the end of the code, simply run Application.Exit(), like so:
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
If My.Application.CommandLineArgs.Count > 0 Then
' Execute (abbreviated) code logic
' When finished, exit the program
Application.Exit()
End If
End Sub
This can also make your code cleaner and more practical if you're relying on a user-interface, because you can still access the values of form elements that the user would otherwise be modifying - but without the form showing on the screen (unless you prompt it to with a MsgBox or such).
This also works very nicely for Scheduled Tasks, as the user can run them manually with a user-interface, while the program executes without being visible via a scheduled task.
Kind of a follow-on to Chad's solution above I used the steps defined in How to have an invisible start up form? to avoid showing my form.
In short, create an Overrides subroutine that gets launched before Form1_Load:
This worked for me:
Protected Overrides Sub SetVisibleCore(ByVal value As Boolean)
If Not Me.IsHandleCreated Then
Me.CreateHandle()
value = False
MyBase.SetVisibleCore(value)
Else
Exit Sub
End If
If My.Application.CommandLineArgs.Count > 0 Then
MsgBox("Argument Sensed!")
' Execute (abbreviated) code logic
' When finished, exit the program
Me.Close()
Application.Exit()
Else
MyBase.SetVisibleCore(True)
End If
End Sub

How to call another module without returning to the first one after completion?

This is probably the dumbest question I've ever asked here, but it's hard to find answers to things like this.
I have a program with a bunch of modules/subs that each calculate a different variable. They're pretty complex, so I like to keep them separate. Now I want an earlier module to skip to another module based on user input. I thought I could use the call (sub name) method for this, but then the program returns to where the call line was and continues on that module from where it left off.
Example:
Module 1:
Sub NewPracticeSub()
Call otherpracticesub
MsgBox ("We've gone back to this sub... :(")
End Sub
Module 2:
Sub otherpracticesub()
MsgBox ("We're in the other practice sub!")
End Sub
I don't want it to return to Module 1. What can I do to have it switch control to Module 2 without it then returning to complete Module 1 upon completion of Module 2?
I feel like I just used the most confusing language possible to explain all of this, but thank you for your help anyways!!
Edit: I know I used the words module and sub interchangeably, and I know they're different. I like to keep each sub (which are each very large in my program) in their own modules because it's easier to keep track of them, and easier to explain/demonstrate the application flow to other people.
I think all you're looking for is the command Exit Sub which will make the program leave the subroutine without continuing any further, But the way you usually want to do this is, rather than calling a Sub, rather call a Function that returns a boolean value.
So, for example:
Public Function MyFunc() as Boolean
....
If [good] MyFunc = True
Else MyFunc = False
End Function
Then you could do something along the lines of:
Sub MyCallingSub()
...
If MyFunc = True then Exit Sub
Else ...
End Sub
It just adds in A LOT more felxibility and ability to choose whether you want to continue further in your sub or not.
Hope that makes sense.
Other than using the ugly End statement which I will describe below (and strongly recommend you to avoid), I'm not aware of any way to circumvent the call stack. Even John's response necessarily returns to the calling procedure, and evaluates another statement to determine whether to proceed or end.
This may yield undesirable outcomes, which is why I hesitate to recommend it, in favor of properly structuring your code, loops, etc., with respect to the call stack.
In any case, here is how you can use the End statement within your child subroutines, without needing any sort of public/global variables. This still allows you the flexibility to decide when & where to invoke the End statement, so it need not always be invoked.
Sub NewPracticeSub()
Call otherpracticesub, True
MsgBox ("We've gone back to this sub... :(")
End Sub
Sub otherpracticesub(Optional endAll as Boolean=False)
MsgBox ("We're in the other practice sub!")
If endAll then End '## Only invoke End when True is passed to this subroutine
End Sub
Why I say this method should be avoided, via MSDN:
"Note The End statement stops code execution abruptly, without
invoking the Unload, QueryUnload, or Terminate event, or any other
Visual Basic code. Code you have placed in the Unload, QueryUnload,
and Terminate events of forms and class modules is not executed.
Objects created from class modules are destroyed, files opened using
the Open statement are closed, and memory used by your program is
freed. Object references held by other programs are invalidated.
The End statement provides a way to force your program to halt. For
normal termination of a Visual Basic program, you should unload all
forms. Your program closes as soon as there are no other programs
holding references to objects created from your public class modules
and no code executing."
It will always return but that doesn't mean its a problem. I suggest you use Exit Sub as follows:
Sub NewPracticeSub()
Call otherpracticesub
**Exit Sub**
'Nothing more can execute here so its no longer a worry
End Sub
Module 2:
Sub otherpracticesub()
MsgBox ("We're in the other practice sub!")
End Sub