The initialization procedures register two window classes, one for the main overlapping window and one for the child windows where the threads draw. They also create a timer. At five-second intervals, the list box updates the information about each thread. The CreateWindows function creates and positions all the windows, including the list box that shows information about each thread. The four threads are created during the WM_CREATE message handler.
/*—————————————————————————————————————————————————————————————————————
WIN MAIN
Calls initializing procedures and runs the message loop
—————————————————————————————————————————————————————————————————————*/
int WINAPI WinMain( HINSTANCE hinstThis, HINSTANCE hinstPrev,
LPSTR lpszCmdLine, int iCmdShow )
{
MSG msg;
hInst = hinstThis; // store in global variable
if( ! InitializeApp( ) )
{
// if the application was not initialized, exit here
return( 0 );
}
ShowWindow( hwndParent, iCmdShow );
UpdateWindow( hwndParent );
// receive and forward messages from our queue
while( GetMessage( &msg, NULL, 0, 0 ) )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
return( msg.wParam );
}
NOTE
Note the absence of a PeekMessage loop in WinMain. That’s a clear sign that you have entered the world of preemptive multitasking. (In preemptive multitasking, the system interrupts executing threads to permit other threads access to the CPU; in permissive multitasking the system waits for a thread to relinquish control of the CPU.) The threads can draw continuously without monopolizing the processor. Other programs can still run at the same time.
In addition to registering the application class and following the usual setup procedures, the InitializeApp procedure sets the thread priority and starts each thread in a suspended state.
/*——————————————————————————————————————————————————————————————————————————
INITIALIZE APP
Register two window classes and then create the windows
——————————————————————————————————————————————————————————————————————————*/
BOOL InitializeApp ( void )
{
...
// mark the initial state of each thread as SUSPENDED
// that is how they will be created
for( iCount = 0; iCount < 4; iCount++ )
{
iState[iCount] = SUSPENDED;
}
// make the primary thread more important to facilitate user i/o
SetThreadPriority( GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL );
// create all the windows
return( CreateWindows( ) );
}
The call to SetThreadPriority increases the priority of the primary thread. If all the secondary threads were busy working at the same priority as the main thread, the menus would respond sluggishly. You can test this yourself by raising the priority of the secondary threads as the program runs.
The CreateWindows function creates not only the main window but also a list box and a series of child windows for the threads.
/*—————————————————————————————————————————————————————————————————————
CREATE WINDOWS
Create the parent window, the list box window, and the four child windows.
—————————————————————————————————————————————————————————————————————*/
BOOL CreateWindows ( void )
{
char szAppName[MAX_BUFFER];
char szTitle[MAX_BUFFER];
char szThread[MAX_BUFFER];
HMENU hMenu;
int iCount;
// load the relevant strings
LoadString( hInst, IDS_APPNAME, szAppName, sizeof(szAppName));
LoadString( hInst, IDS_TITLE, szTitle, sizeof(szTitle));
LoadString( hInst, IDS_THREAD, szThread, sizeof(szThread));
// create the parent window
hMenu = LoadMenu( hInst, MAKEINTRESOURCE(MENU_MAIN) );
hwndParent = CreateWindow( szAppName, szTitle,
WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
NULL, hMenu, hInst, NULL );
if( ! hwndParent )
{
return( FALSE );
}
// create the list box
hwndList = CreateWindow( “LISTBOX”, NULL,
WS_BORDER | WS_CHILD | WS_VISIBLE |
LBS_STANDARD | LBS_NOINTEGRALHEIGHT,
0, 0, 0, 0, hwndParent, (HMENU)1,
hInst, NULL );
if( ! hwndList )
{
return( FALSE );
}
// create the four child windows
for( iCount = 0; iCount < 4; iCount++ )
{
hwndChild[iCount] = CreateWindow( “ThreadClass”, NULL,
WS_BORDER | WS_CHILD |
WS_VISIBLE | WS_CLIPCHILDREN,
0, 0, 0, 0, hwndParent, NULL,
hInst, NULL );
if( ! hwndChild ) return( FALSE );
}
return( TRUE );
}