You haven't posted code that demonstrates the problem.
How do you get the code to loop, that is, where is the loop, how did you get it started?
Normally you shouldn't be using DoEvents. You could be running the loop in a background thread.

But for sake of argument and a quick test example, this code had no problem exiting the loop on the first click of the button that sets the boolean flag.
The sub that loops is called by one button, and another button sets the flag to have the loop exit.

I assume it is because you're calling the sub from a button event, that event never completes, so the button up event gets hung up. By disabling the button frees up the event processing so the next button event is processed correctly.
If you don't disable the button the next button press is consumed internally somehow in windows in getting its event processing back in sync, so it takes one to "clean up", then normal button processing will work again.

Perhaps since you (apparently) need to draw in a continuous loop (instead of from a periodic event, like a timer tick), and you're using .Net, a different paradigm is needed.
Do your drawing in a background thread.
If you use a Buffered Graphics object your background thread can draw in it, and have it render to a control's area of the screen. It is technically not accessing the control or using it to draw so you don't have a cross threading issue.
Just don't drawn on that control from the GUI because it will be clobbered by the drawing from the background thread.
Don't know your complete situation though.

Here is a quick simple example that uses a Buffered Graphics object and a background thread to draw on the screen in the area "above" a panel.
To demonstrate it is drawing to the panel area, the example allows you to drag on the panel to move it around, while the background thread continues to draw to the screen area associated with that panel.

So, create a new project and add a panel to it, and make it whatever size you want, paste in the code and run it. Drag on the panel and see the drawing continue as the panel moves.
Another advantage to the background thread drawing to a Buffered Graphics object, is it continues to draw where drawing from the GUI pauses on some user interaction with the window, such as clicking down on the title bar of a window.
This also exits fine, it pauses for 1/10th of a second during closing to allow the loop to exit in the background thread. How long you have to pause depends on the frequency of your background thread loop.

I'm finding out that in a normal loop in a single
thread, the loop pulls the focus from all controls,
including the form. That is why i have to click
twice on the buttons to stop the drawing process
or click twice on the big red x button on the form
to close it.

The loop will exit on form closing when i use an
Application.Exit and the IDE goes back into design
mode.

I kind of like the background worker thread though
because you can move the form or do other stuff and
the drawing continues on. I like that aspect of it.

Like i said earlier though, i was getting an error, every
time i ran my program in the new thread. It was
complaining about using a picturebox object that was
still in use.

picMap.Image = MapBmp <-- Error here

The error is say: Object is currently in use elsewhere

I somewhat resolved that problem by eliminating every
picMap.Image = MapBmp in my code and only calling
that once in my loop. That works and all animations draw
correctly but there is still a problem.

When i resize the form and cover up some of the picturebox
(picMap), i get the same error. Now that i think of it, i'll try
using a try statement at that point to see if the helps.

According to MS, if you use a Synclock

Synclock(picMap)
' Code goes here
End Synclock

That is suppose to stop that kind of error from happening
but it doesn't.

It looks like the ThreadState has goes through many changes
from VB Net's very beginnings till now. A lot of the good
threadstates are now depreciated and no long used. So why
does MS still include them in the new versions of vb. For
backwards compatibility?

Anyway, just thought i'd give you an update on my problem.

No sure if i really need any help at this point. I'll post again
if i do.

Didn't look at my computer much at all this past weekend.
I'll look at your program tonight.
The issue is either that you're trying to access a GUI control from a background thread, which you can't do, you have to Invoke back to the GUI thread and access the control from there. That is the "paradigm" shift. You have to manage your drawing yourself and not use any GUI control methods, such as the paint event, to do any drawing.
Having code in the paint event I suspect is the problem with the picturebox being covered up.

The other possibility, since the error seems to indicate an object busy fault, not a control access fault, is you can't access an object from two threads at the same time.
A syncLock could help that, but it is best to avoid using the same object from multiple threads if the design allows it.

The StopWatch object essentially wraps access to the QueryPerformanceCounter in .Net, so you can use that more conveniently than having to use the API directly.

<edit>
I did some looking at your project.
I didn't relook at NOI_Max old VB6 code, and I assume he didn't have this mistake, but I was looking at the HpTimer.vb code to see how it looked, to see how one might replace it with a stopwatch object.
One think I noticed was it was taking a relatively large amount of time to complete each animation loop, more than I would have expected.
I started printing out the elapsed time each loop, and commenting out some things.
It turns out the drawing was what was taking the most time, so I looked at those animation code loops.
It looks like most of them have the "End If" in the wrong place (in front of the g.DrawImage call).
So you are drawing something for every tile of the map in every animation routing (except one sub, I think is correct).
The g.DrawImage should be inside the If Block, so that you only draw the animation tile once for each instance of that particular animation tile. You are essentially drawing each animation tile 77 times each frame.

__________________
There Is An Island Of Opportunity In The Middle of Every Difficulty.
Miss That, Though, And You're Pretty Much Doomed.

Yes. It was an object busy fault. I put picMap.image = MapBmp
in the picmap paint event. Now picmap doesn't get called at all
in the background thread. Thanks for that idea.

I totally missed the drawing being done outside the if statement.
I put them all inside it. Thanks for pointing that out.

Some day, i may play with the stopwatch timer but for now, i'm
liking the QueryPerformanceCounter very much and i'm not ready
to scrap it out yet. It works very well, even in vb net. I think a
lot of programmers are still using it.