If there are no messages queued, the GetMessage() function does not return control to your program. Windows allows execution to pass to another application, and you will only get a value returned from calling GetMessage() when a message appears in the queue.
This mechanism was fundamental in enabling multiple applications to run under older versions of Windows and is referred to as cooperative multitasking because it depends on concurrent applications giving up control of the processor from time to time. After your program calls GetMessage(), unless there is a message for it another application is executed and your program gets another opportunity to do something only if the other application releases the processor, perhaps by a call to GetMessage() when there are no messages queued for it, but this is not the only possibility.
With current versions of Windows, the operating system can interrupt an application after a period of time and transfer control to another application. This mechanism is called pre-emptive multitasking because an application can be interrupted at any time. With pre-emptive multitasking, however, you must still program the message loop in WinMain() using GetMessage() as before, and make provision for relinquishing control of the processor to Windows from time to time in a long-running calculation (this is usually done using the PeekMessage() API function). If you don’t do this, your application may be unable to respond to messages to repaint the application window when these arise. This can be for reasons that are quite independent of your application — when an overlapping window for another application is closed, for example."
Can anyone please simplify everything in those 3 paragraphs?
Windows, Unix and Linux are examples of preemptive multitasking operating systems. Your programs runs in their own threads of execution and the operating system decides what to run and when.
Not all operating systems are like that, but still manage to run programs apparently simultaneously.
WIN16 is one such example. It works by having the program process tiny chunks of code non-preemptively. But when each chunk is done, control can be passed to another program. While one program is running its chunk, nothing else can run. The chunk is a Window message handler.
Java Green threads and Unix user threads are all non-preemptive implementations where the scheduling is done in a user space library. I/O is a good signal and opportunity to do a context switch.
As an aside, as WIN16 did not have any hardware assistance:
* all programs had to cooperate to simulate concurrency and achieve system reliability
* leaked resources could not be recovered
* a single app could corrupt the system heap
* a single app could crash the system
But remember, it ran a GUI quickly and competently (if not reliably) on a 16MHz 386sx CPU with 2M of memory. It was no slower than Vista on a 2GHz multi-core CPU with 2G of memory.