File:  [OS/2 SDKs] / os232sdk / toolkt20 / c / samples / template / thrd.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Thu Aug 9 12:26:31 2018 UTC (7 years, 9 months ago) by root
Branches: msft, MAIN
CVS tags: os2sdk-1990, HEAD
Microsoft OS/2 SDK 2.0 05-30-1990

/*==============================================================*\
 *  Thrd.c - background thread and associated routines
 *      Created 1989, 1990 Microsoft Corp.
 *--------------------------------------------------------------
 *
 *  This module contains the code for a background processing
 *  thread as well as the code for any routines used in that thread.
 *
 *  This thread uses an object window to facilitate communication
 *  with the main thread.  The main thread can communicate with
 *  the background thread through messages.  You define your
 *  own window messages in main.h, post or send them to the
 *  background thread through the routines provided in this file,
 *  and then process the messages in the ObjectWndProc() routine.
 *  The object window then sends other messages back to the
 *  main window to notify the main window as to the status of the
 *  task or with the final result.
 *
 *  An object window is used as the main window of the thread
 *  for several reasons.  The window is hidden, so it is never
 *  displayed on the screen.  Since it is hidden, the window
 *  does not have to process most of the window messages that are
 *  processed by visible windows, e.g. WM_PAINT, WM_SIZE,
 *  WM_SETFOCUS, etc.  This window will never receive the focus
 *  so it does not have to process input messages.  You can, however,
 *  send all mouse and keyboard messages to this window and have
 *  it process all input if you wish.  Since the window does not
 *  belong to any focus or activation chains, you can block this
 *  thread on a semaphore without having the system lock up or use
 *  the window manager semaphore routines (WinMsgSemWait(), etc.).
 *
 *  NOTE:  The BackgroundThread() routine is designed to create only
 *          one thread.  In fact, should you try to create another
 *          one the call will fail.  The thread uses several variables
 *          which are defined globally within this module.  In order
 *          to enable this routine to create multiple threads, you
 *          will need to make these variables local.  You will also need
 *          to differentiate between the different object windows
 *          created so that you can specify which thread will
 *          receive a posted message.
 *
 *  In order to enable the use of the second thread, define the
 *  BACKGROUND_THREAD constant found in main.h
 *
 *--------------------------------------------------------------
 *
 *  This source file contains the following functions:
 *
 *      BackgroundThread() - routine for the background thread
 *      CreateBackgroundThread() - routine that creates background thread
 *      DestroyBackgroundThread() - routine that destroys the thread
 *      PostBkThreadMsg(msg, mp1, mp2) - posts a msg to the thread
 *      SendBkThreadMsg(msg, mp1, mp2) - sends a msg to the thread
 *      ObjectWndProc(hwnd, msg, mp1, mp2) - Object window procedure
 *
\*==============================================================*/

/*--------------------------------------------------------------*\
 *  Include files, macros, defined constants, and externs
\*--------------------------------------------------------------*/

#define  INCL_DOSPROCESS
#define  INCL_DOSSEMAPHORES

#include <os2.h>
#include "main.h"
#include "xtrn.h"

#define THREADSTACKSIZE     8192L
#define SEM_TIMEOUT        10000L

/*--------------------------------------------------------------*\
 *  Global variables
\*--------------------------------------------------------------*/
static HAB habBkThread;
static HMQ hmqBkThread;
static TID tidBkThread;
static HWND hwndObject;
static CHAR szObjectClass[MAXNAMEL];
static BOOL fThreadCreated = FALSE;
static HEV hevThreadInit;   /* semaphore for thread initialization */

/*--------------------------------------------------------------*\
 *  Entry point declarations
\*--------------------------------------------------------------*/
VOID BackgroundThread(ULONG ulThreadParam);
MRESULT EXPENTRY ObjectWndProc(HWND hwnd, USHORT msg, MPARAM mp1, MPARAM mp2);


/****************************************************************\
 *  Background thread routine
 *--------------------------------------------------------------
 *
 *  Name:   BackgroundThread(ulThreadParam)
 *
 *  Purpose: Routine is a background thread used for tasks to be
 *           completed in the background.
 *
 *  Usage:  Routine is called at initialization time to create
 *          a background processing thread.
 *
 *  Method: The routine initializes itself as a PM thread and creates
 *          a message queue.  It then creates an object window
 *          through which it will receive and send messages.
 *          It then polls through a message loop, processing any
 *          messages it receives in the object window's window
 *          procedure.  When the loop ends, it terminates.
 *
 *  Returns:
 *
\****************************************************************/
VOID BackgroundThread(ulThreadParam)
ULONG ulThreadParam;        /* parameter passed into DosCreateThread() */
{
    QMSG qmsg;

    /* create message queue for thread */
    habBkThread = WinInitialize(0);
    if(habBkThread == NULL)  {
        WinPostMsg(hwndMain, TM_THREADINITFAILED, NULL, NULL);
        DosExit(EXIT_THREAD, NULL);
    }

    hmqBkThread = WinCreateMsgQueue(habBkThread, 0);
    if(hmqBkThread == NULL)  {
        WinPostMsg(hwndMain, TM_THREADINITFAILED, NULL, NULL);

        WinTerminate(habBkThread);
        DosExit(EXIT_THREAD, NULL);
    }

    /* load the string for the object window class and register the class */
    if(!WinLoadString(habBkThread,
                      NULL,
                      IDS_OBJECTCLASS,
                      MAXNAMEL,
                      (PSZ)szObjectClass))  {
        WinPostMsg(hwndMain, TM_THREADINITFAILED, NULL, NULL);

        goto ExitBkThread;
    }

    /* register the main client window class */
    if(!WinRegisterClass(habBkThread,
                        (PSZ)szObjectClass,
                        (PFNWP)ObjectWndProc,
                        0,
                        0))  {

        WinPostMsg(hwndMain, TM_THREADINITFAILED, NULL, NULL);

        goto ExitBkThread;
    }


    /* create the object window */
    hwndObject = WinCreateWindow(HWND_OBJECT,
                                 szObjectClass,
                                 NULL,
                                 NULL,
                                 0,
                                 0,
                                 0,
                                 0,
                                 NULL,
                                 HWND_TOP,
                                 OBJECTID,
                                 NULL,
                                 NULL);

    if(hwndObject == NULL)  {
        WinPostMsg(hwndMain, TM_THREADINITFAILED, NULL, NULL);

        goto ExitBkThread;
    }

    /* set thread created flag so another thread of this type
       cannot be created */
    fThreadCreated = TRUE;

    /* clear initialization semaphore */
    DosPostEventSem(hevThreadInit);


    /* message loop */
    while(WinGetMsg(hmqBkThread, (PQMSG)&qmsg, NULL, NULL, NULL))
        WinDispatchMsg(hmqBkThread, (PQMSG)&qmsg);

ExitBkThread:

    /* destroy object window, clean up message queue and terminate */
    if(WinIsWindow(habBkThread, hwndObject))
        WinDestroyWindow(hwndObject);

    WinDestroyMsgQueue(hmqBkThread);
    WinTerminate(habBkThread);

    /* If termination is due to an error initializing the thread, then
        clear the initialization semaphore so that the main thread
        can continue. */
    if(!fThreadCreated)
        DosPostEventSem(hevThreadInit);


    /*------------------------------------------------------------------*
     *
     *  Note: C-runtime considerations:
     *
     *  If you use non-reentrant C runtime functions in the second thread,
     *  then you should use call _endthread here instead of DosExit().
     *  See the comment in the CreateBackgroundThread() routine for
     *  more information.
     *
     *------------------------------------------------------------------*/
    DosExit(EXIT_THREAD, NULL);

    /* the thread parameter is not currently used */
    ulThreadParam;

}   /* BackgroundThread() */


/****************************************************************\
 *  Creates the Background thread
 *--------------------------------------------------------------
 *
 *  Name:   CreateBackgroundThread()
 *
 *  Purpose: Routine creates the background thread
 *
 *  Usage:  Routine is called at initialization time to create
 *          a background processing thread.
 *
 *  Method: The routine calls DosCreateThread with the Background
 *          thread routine.
 *
 *  Returns: TRUE if thread is created successfully, FALSE if not
 *              or if the thread was already created
 *
\****************************************************************/
BOOL CreateBackgroundThread(VOID)
{
    SHORT sRet;

    /*------------------------------------------------------------------*
     *
     *  Note: C-runtime considerations:
     *
     *  If you use non-reentrant C runtime functions in the second thread,
     *  then you will need to use _beginthread and _endthread instead of
     *  DosCreateThread and DosExit.  In addition, you will have
     *  to link with LIBCMT.LIB instead of LIBC.LIB, and you will
     *  have use -D_MT as a compiler option.
     *
     *------------------------------------------------------------------*/


    if(!fThreadCreated)  {
        DosCreateEventSem((PSZ)NULL, &hevThreadInit, 0L, FALSE);
        sRet = DosCreateThread(&tidBkThread,
                               (PFNTHREAD)BackgroundThread,
                               0L,
                               0L,
                               THREADSTACKSIZE);
    } else
        return FALSE;

    /* wait until the thread has finished initialization */
    if(DosWaitEventSem(hevThreadInit, SEM_TIMEOUT))
        return FALSE;

    return((BOOL)(sRet == 0));

}   /* CreateBackgroundThread() */


/****************************************************************\
 *  Destroys the Background thread
 *--------------------------------------------------------------
 *
 *  Name:   DestroyBackgroundThread()
 *
 *  Purpose: Routine destroys the background thread
 *
 *  Usage:  Routine is called at exit time to destroy the background
 *          processing thread.
 *
 *  Method: The routine posts a WM_CLOSE message to the object window
 *          to end its message loop.  It then waits to make sure that the
 *          thread has been terminated before it returns.
 *
 *  Returns:
 *
\****************************************************************/
VOID DestroyBackgroundThread(VOID)
{

    PostBkThreadMsg(WM_CLOSE, NULL, NULL);

    DosWaitThread(&tidBkThread, 0);

}   /* DestroyBackgroundThread() */


/****************************************************************\
 *  Posts a message to the Background thread
 *--------------------------------------------------------------
 *
 *  Name:   PostBkThreadMsg()
 *
 *  Purpose: Routine posts a message to the object window of the
 *           background thread.
 *
 *  Usage:  Routine is called whenever a message is to be posted to
 *          the background processing thread.
 *
 *  Method: The routine posts the message to the object window of the
 *          thread.
 *
 *  Returns: the return value from WinPostMsg().
 *
\****************************************************************/
BOOL PostBkThreadMsg(msg, mp1, mp2)
USHORT msg;     /* message id */
MPARAM mp1;     /* first parameter */
MPARAM mp2;     /* second parameter */
{

    return(WinPostMsg(hwndObject, msg, mp1, mp2));

}   /* PostBkThreadMsg() */


/****************************************************************\
 *  Sends a message to the Background thread
 *--------------------------------------------------------------
 *
 *  Name:   SendBkThreadMsg()
 *
 *  Purpose: Routine sends a message to the object window of the
 *           background thread.
 *
 *  Usage:  Routine is called whenever a message is to be sent to
 *          the background processing thread.
 *
 *  Method: The routine sends the message to the object window of the
 *          thread.
 *
 *  Returns: the return value from WinSendMsg().
 *
\****************************************************************/
MRESULT SendBkThreadMsg(msg, mp1, mp2)
USHORT msg;     /* message id */
MPARAM mp1;     /* first parameter */
MPARAM mp2;     /* second parameter */
{

    return(WinSendMsg(hwndObject, msg, mp1, mp2));

}   /* SendBkThreadMsg() */


/****************************************************************\
 *  Dialog procedure for the Object window
 *--------------------------------------------------------------
 *
 *  Name:   ObjectWndProc(hwnd, msg, mp1, mp2)
 *
 *  Purpose: Processes all messages sent to the Object window
 *
 *  Usage:  Called for each message sent to the Object window.
 *
 *  Method: the Object window processes the messages that tell
 *          the background thread what action to take.  Since
 *          the object window is not visible, it will not
 *          process any of the standard window messages.
 *
 *  Returns: Dependent upon message sent
 *
\****************************************************************/
MRESULT EXPENTRY ObjectWndProc(hwnd, msg, mp1, mp2)
HWND hwnd;      /* handle of window */
USHORT msg;     /* id of message */
MPARAM mp1;     /* first message parameter */
MPARAM mp2;     /* second message parameter */
{

    switch(msg)  {

        /*--------------------------------------------------------------*\
         *  Include any user defined messages to determine which
         *  action the background thread should take
        \*--------------------------------------------------------------*/

        default:
            return (WinDefWindowProc(hwnd, msg, mp1, mp2));
            break;
    }

    return 0L;

    hwnd;
    mp1;
    mp2;

}   /* ObjectWndProc() */

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.