Window Thread Control Thread

In old DOS programs, you would write programs that drew on the screen and called "getkey" to get input. Such programs could call "getkey" from multiple places. Thus, the program had to indicate to the user which place he was in.

In single-threaded Windows programs, you have a window procedure which is called when input arrives. So where you had multiple calls to "getkey" before, you must now have a "state" variable and you must switch off according to which state you are in. (This is assuming you want the exact same behavior as the DOS program.)

In old DOS programs, each occurrence of "getkey" could be considered a state or a mode, and you'd write your code to show specifically how to get from one mode to another. You'd have all the control structures of the language to use to express this. You could use functions to show states that you can enter into and return from.

In object-oriented designs, you typically have to implement a state machine in order to support an object with a bunch of modes. If you want to use a mode as a "subroutine" which you can "return" from, then you'll need another variable for the "old" mode, or perhaps even a stack!

Microsoft will tell you that they think users prefer programs that have only one mode, but the issue is broader than just windows: any object's method calls can be viewed as events, and sometimes an object's design would be clearer if you could pretend you were calling a "get event" function from inside the object instead of having to write method calls that have to check the object's state and manipulate it accordingly. UnifiedModelingLanguage, I think, has a whole set of diagrams for states.

It's much better, I think, to set up CoRoutines to handle this. ErlangLanguage, from a certain point of view, allows each object to have its own coroutine. SchemeLanguage gives you CallWithCurrentContinuation, which makes it easy to construct coroutines.

It is also possible to do it with threads. Make your object set up a thread which waits for events. Then make method calls send events to that thread, and receive results from it. The thread can then call "get event," from multiple places depending on what state it is in, and retrieve an object describing the method call. It can send back the return value in the same way.

It is very interesting to write Windows programs this way. When I do it, I usually set up the Main routine as a "control thread," and then it creates a window object with methods such as "draw something on yourself" and "get me the next keypress." The window object has a captive thread, a "window thread," which runs a regular Windows message loop and receives these method calls as a flavor of WM_USER, along with all the messages from Windows. It can be configured so that when the control thread is busy, it displays an hourglass, and when the control thread is awaiting a key and it has the focus, it displays the caret.

It's also possible to do it the other way around, so that the window thread is the "main" thread. On the other hand, it seems like you could do all this without threads by calling GetMessage directly. (I've never tried that...)

Such a programming method makes it much easier to write programs where windows have "modes" or expect inputs in certain sequences.

-- EdwardKiser

If you call GetMessage directly from multiple places in your code you will also need a way to handle all of the messages from Windows at all of those places. For example, your program is in state A in which it expects one of two possible events to move it to either state B or state C, but along comes a WM_PAINT because the user has closed another program uncovering more of your window. I'm not saying this is impossible, or even difficult, but there are a rather large set of Windows messages that can occur at arbitrary moments due to external events and your program needs to handle them as soon as they arrive to avoid appearing unresponsive.

Also note that the "window thread" must be the one that creates its window, otherwise it won't get its messages.


EditText of this page (last edited June 16, 2004) or FindPage with title or text search