Exiting while loop in winapi - winapi

My problem is this. I have check box which when checked starts while loop. At that while loop there is createprocess function. While checkbox is marked as checked, function repeats it self again and again. Problem is that while loop is running I can't push check box again to change it's values and stop the process. I think that here is needed something like two parallel process working at the same time, but I am not sure. My question would be:
* Is there a way to access my controls while while loop is running?
* Or maybe I should use something else instead of while process?
Suggestions or some kind of example would be appreciated.

The problem is that you are running the loop in the same thread that owns the CheckBox, and that loop is blocking the thread from processing new messages. That is why you are not able to uncheck the CheckBox (or do anything else with your UI).
You need to either:
move the loop to a worker thread. When the CheckBox becomes checked, start the thread. When the CheckBox becomes unchecked, stop the thread. Do not block the dialog's thread at all. This is the best option.
break apart your loop and make it event-driven. When the CheckBox becomes checked, post a custom window message to yourself. When you receive that message, if the CheckBox is still checked then perform one iteration of your loop and then post the message back to yourself again. Repeat until the CheckBox becomes unchecked. This option does not require any threads, but your UI will still be blocked during each individual iteration (but you will be able to uncheck the CheckBox in between iterations), unless...
Keep your existing loop code, but add an inner loop that calls MsgWaitForMultipleObjects() after CreateProcess() succeeds until the spawned process has exited. While waiting, whenever MsgWaitForMultipleObjects() tells you that a new message is waiting, you can pump the message queue and dispatch any messages that are retrieved. This is the least desirable option, but it requires the least amount of changes to existing code.

Related

Why does assert_no_selector() wait until the wait time is over even if the element is found?

I am checking a webpage for a certain element using assert_selector and assert_no_selector.
In one context, the element is present, and in one of them it is not. My tests are working properly. However, if I use assert_no_selector when the element is on the page, instead of the test failing immediately, it waits until the default_max_wait_time specified in my helper file before it fails and moves on to the next test. For example
scenario 'expect element to appear' do
login(email, password)
assert_no_selector('a[id="elementID"]', minimum: 1)
end
I would assume that if this code is run and the element is in fact located on the page, then it would immediately fail. Why does it wait until the max wait time has been reached even though the element is probably found very quickly? Is there a better way to do this? I would like to avoid having the test wait the entire max wait time whenever this test fails.
The purpose of the waiting behavior in Capybaras assertions is to deal with asynchronous behavior in a browser. If you use assert_no_selector you are telling capybara that you expect the page not to have that element, so it will wait up to the maximum wait time for that element to go away before raising an exception (because you're telling it you expect that element not to be there and the page may be processing something that would cause that element to be removed). If you want an immediate check then specify a wait of 0 - but that will generally lead to flaky tests once you have JS behaviors in the page.
assert_no_selector('a#elementID', wait: 0)

How does NSUndoManager.groupsByEvent determine the current run loop pass?

I'd like to understand/replicate the "group by run loop pass/cycle" feature of NSUndoManger:
NSUndoManager can group multiple calls to registerUndo() into a single "undo" operation when invoked multiple times on the same run loop cycle. This is determined by NSUndoManager.groupsByEvent, which is set to true by default.
So something like this:
// User clicks button... (causes a new run loop event)
undoManager.registerUndo(...) // #1
undoManager.registerUndo(...) // #2
...results in one undo group and clicking Edit → Undo reverts both changes at once.
Somehow NSUndoManager can figure out if two calls to registerUndo() are on the same run loop cycle. How does this work?
My use case:
I have code that sends property change notifications after the user interacts with the UI (e.g. clicks a button). There can be one or more events as the result of a user action. I'd like to group those and update the UI only once at the end of the current run loop.
NSUndoManager normally creates undo groups automatically during the run loop. The first time it is asked to record an undo operation in the run loop, it creates a new group. Then, at the end of the loop, it closes the group.
source: Undo Operations and Groups
NSUndoManager is part of the same framework as NSRunLoop so maybe NSRunLoop signals NSUndoManager to close a group. You don't know and you shouldn't want to know.

without using DoEvents, how to detect if a button has been pressed?

Currently, I call DoEvents in order to check if Button Foo in Form Bar has been clicked. This approach works but it takes too much processing power, delaying the program.
I believe that the delay could be reduced if I could only check if Button Foo has been clicked, instead of all the other forms that DoEvents has to go through.
Any ideas on how can I check if Button Foo was clicked?
VB6 was not really designed for what you seem to be doing (some sort of long-running straight-line code that does not exit back to give the message loop control). Normally such a task would be delegated to a worker thread, and in VB6 this means some external component implemented in C++ most of the time.
There are only a very few kinds of approaches to take to do this for your ad-hoc logic:
Hacks creating separate threads via API calls, not very reliable in VB6 for a number of reasons.
A tricky thread-per-object ActiveX EXE implementing a class to handle your long-running workload.
A separate non-interactive worker process to be run and monitored by your GUI program.
That's pretty much it.
The prescribed method of doing this sort of thing is described in the VB6 documentation. You break your long-running loop up and invert the logic into a repeatable "quantum" of work (like n iterations of your processing loop), and maintain the state of your workload in Form-global data. Then you use a Timer control with its interval set to 1 or 16 (hardly matters, they normally take at least 16ms to trigger) and run your workload quantum within its event handler.
So if you simply had a loop that currently iterates 100,000 times doing something you might break it up so that it runs 500 times for each Timer tick. The quantum size will probably need to be tuned based on what is done within the loop - 500 is just a value chosen for illustration. You'll want to adjust this until it leaves the UI responsive without starving your background workload too much (slowing completion down).
If your code is heavy enough to not call DoEvents or just finish running periodically, then your app won't even know the button has been pressed. The DoEvents call allows windows, and your application to catch up on all notifications.
The correct way to resolve this is a worker thread (see this article on how to do something like this in VB6) but failing that, a periodic DoEvents is required and in turn, some re-entrancy blocking on the call into the long running code.

What is a browser event loop?

I have been doing some web application programming using GWT and have been confused by the term "browser event loop".
I have encountered situations where I need to execute deferred commands and "do something" after the browser event loop completes.
I would like to know as to what exactly it is and what happens during the event loop process and in which order?
A browser event loop is a thread started by the browser that is constantly scanning for and running different events, just like it sounds. As events occur they are put in the event queue and run in turn by the one event thread. Your javascript should not create its own loops waiting for it to complete or anything like that...it will block that one continuous event loop thread. Instead you would use something like setTimeout or setInterval and check for whatever conditions you are waiting for so the browser can do work while it 'waits'.
GWT is nice in that it can co-opt this process somewhat using the scheduler -- in your case where you want to run something after the event loop 'completes' you will probably want to use scheduleFinally or scheduleDeferred. It will inject a handler for a piece of code into the event queue so that it will run after all other code in the current execution context (current execution context == where ever you are in the current JavaScript object hierarchy with the window as the root object) is run but before the next event that is placed in the queue.

a nonresponsive program, doesn't end gracefully when asked to terminate, for testing

I want to write a simple program that does nothing but does not easily terminate when asked to. I want to see the Windows dialog box which says, "this program is not responsive, do you want to wait to let it finish what it's doing, or terminate it now?". After the user chooses "terminate it now", it should, of course, exit.
The reason I want this is for a testing environment. I want to test a scenario in which the user is trying to log out, but the system doesn't log them out right away, because of an unresponsive program.
I tried responding to WM_DESTROY by calling Sleep(), but that doesn't seem to do it. The program still terminates immediately when killed from the Task Manager. Again, I'm not trying to write something truly "unkillable", just a simple program which makes that dialog box come up asking if the user wants to wait for the program to finish.
Thanks very much for any help.
You can try modifying your main-message loop . Use PeekMessage(...) with NO_REMOVE and ignore WM_QUIT messages
EDIT: Remove every message (except WM_QUIT) before processing it (GetMessage( &msg ,msg.hWnd ,msg.message ,msg.message ))

Resources