|
|
1.1 ! root 1: /*==============================================================*\ ! 2: * Thrd.c - background thread and associated routines ! 3: * Created 1989, 1990 Microsoft Corp. ! 4: *-------------------------------------------------------------- ! 5: * ! 6: * This module contains the code for a background processing ! 7: * thread as well as the code for any routines used in that thread. ! 8: * ! 9: * This thread uses an object window to facilitate communication ! 10: * with the main thread. The main thread can communicate with ! 11: * the background thread through messages. You define your ! 12: * own window messages in main.h, post or send them to the ! 13: * background thread through the routines provided in this file, ! 14: * and then process the messages in the ObjectWndProc() routine. ! 15: * The object window then sends other messages back to the ! 16: * main window to notify the main window as to the status of the ! 17: * task or with the final result. ! 18: * ! 19: * An object window is used as the main window of the thread ! 20: * for several reasons. The window is hidden, so it is never ! 21: * displayed on the screen. Since it is hidden, the window ! 22: * does not have to process most of the window messages that are ! 23: * processed by visible windows, e.g. WM_PAINT, WM_SIZE, ! 24: * WM_SETFOCUS, etc. This window will never receive the focus ! 25: * so it does not have to process input messages. You can, however, ! 26: * send all mouse and keyboard messages to this window and have ! 27: * it process all input if you wish. Since the window does not ! 28: * belong to any focus or activation chains, you can block this ! 29: * thread on a semaphore without having the system lock up or use ! 30: * the window manager semaphore routines (WinMsgSemWait(), etc.). ! 31: * ! 32: * NOTE: The BackgroundThread() routine is designed to create only ! 33: * one thread. In fact, should you try to create another ! 34: * one the call will fail. The thread uses several variables ! 35: * which are defined globally within this module. In order ! 36: * to enable this routine to create multiple threads, you ! 37: * will need to make these variables local. You will also need ! 38: * to differentiate between the different object windows ! 39: * created so that you can specify which thread will ! 40: * receive a posted message. ! 41: * ! 42: * In order to enable the use of the second thread, define the ! 43: * BACKGROUND_THREAD constant found in main.h ! 44: * ! 45: *-------------------------------------------------------------- ! 46: * ! 47: * This source file contains the following functions: ! 48: * ! 49: * BackgroundThread() - routine for the background thread ! 50: * CreateBackgroundThread() - routine that creates background thread ! 51: * DestroyBackgroundThread() - routine that destroys the thread ! 52: * PostBkThreadMsg(msg, mp1, mp2) - posts a msg to the thread ! 53: * SendBkThreadMsg(msg, mp1, mp2) - sends a msg to the thread ! 54: * ObjectWndProc(hwnd, msg, mp1, mp2) - Object window procedure ! 55: * ! 56: \*==============================================================*/ ! 57: ! 58: /*--------------------------------------------------------------*\ ! 59: * Include files, macros, defined constants, and externs ! 60: \*--------------------------------------------------------------*/ ! 61: ! 62: #define INCL_DOSPROCESS ! 63: #define INCL_DOSSEMAPHORES ! 64: ! 65: #include <os2.h> ! 66: #include "main.h" ! 67: #include "xtrn.h" ! 68: ! 69: #define THREADSTACKSIZE 8192L ! 70: #define SEM_TIMEOUT 10000L ! 71: ! 72: /*--------------------------------------------------------------*\ ! 73: * Global variables ! 74: \*--------------------------------------------------------------*/ ! 75: static HAB habBkThread; ! 76: static HMQ hmqBkThread; ! 77: static TID tidBkThread; ! 78: static HWND hwndObject; ! 79: static CHAR szObjectClass[MAXNAMEL]; ! 80: static BOOL fThreadCreated = FALSE; ! 81: static HEV hevThreadInit; /* semaphore for thread initialization */ ! 82: ! 83: /*--------------------------------------------------------------*\ ! 84: * Entry point declarations ! 85: \*--------------------------------------------------------------*/ ! 86: VOID BackgroundThread(ULONG ulThreadParam); ! 87: MRESULT EXPENTRY ObjectWndProc(HWND hwnd, USHORT msg, MPARAM mp1, MPARAM mp2); ! 88: ! 89: ! 90: /****************************************************************\ ! 91: * Background thread routine ! 92: *-------------------------------------------------------------- ! 93: * ! 94: * Name: BackgroundThread(ulThreadParam) ! 95: * ! 96: * Purpose: Routine is a background thread used for tasks to be ! 97: * completed in the background. ! 98: * ! 99: * Usage: Routine is called at initialization time to create ! 100: * a background processing thread. ! 101: * ! 102: * Method: The routine initializes itself as a PM thread and creates ! 103: * a message queue. It then creates an object window ! 104: * through which it will receive and send messages. ! 105: * It then polls through a message loop, processing any ! 106: * messages it receives in the object window's window ! 107: * procedure. When the loop ends, it terminates. ! 108: * ! 109: * Returns: ! 110: * ! 111: \****************************************************************/ ! 112: VOID BackgroundThread(ulThreadParam) ! 113: ULONG ulThreadParam; /* parameter passed into DosCreateThread() */ ! 114: { ! 115: QMSG qmsg; ! 116: ! 117: /* create message queue for thread */ ! 118: habBkThread = WinInitialize(0); ! 119: if(habBkThread == NULL) { ! 120: WinPostMsg(hwndMain, TM_THREADINITFAILED, NULL, NULL); ! 121: DosExit(EXIT_THREAD, NULL); ! 122: } ! 123: ! 124: hmqBkThread = WinCreateMsgQueue(habBkThread, 0); ! 125: if(hmqBkThread == NULL) { ! 126: WinPostMsg(hwndMain, TM_THREADINITFAILED, NULL, NULL); ! 127: ! 128: WinTerminate(habBkThread); ! 129: DosExit(EXIT_THREAD, NULL); ! 130: } ! 131: ! 132: /* load the string for the object window class and register the class */ ! 133: if(!WinLoadString(habBkThread, ! 134: NULL, ! 135: IDS_OBJECTCLASS, ! 136: MAXNAMEL, ! 137: (PSZ)szObjectClass)) { ! 138: WinPostMsg(hwndMain, TM_THREADINITFAILED, NULL, NULL); ! 139: ! 140: goto ExitBkThread; ! 141: } ! 142: ! 143: /* register the main client window class */ ! 144: if(!WinRegisterClass(habBkThread, ! 145: (PSZ)szObjectClass, ! 146: (PFNWP)ObjectWndProc, ! 147: 0, ! 148: 0)) { ! 149: ! 150: WinPostMsg(hwndMain, TM_THREADINITFAILED, NULL, NULL); ! 151: ! 152: goto ExitBkThread; ! 153: } ! 154: ! 155: ! 156: /* create the object window */ ! 157: hwndObject = WinCreateWindow(HWND_OBJECT, ! 158: szObjectClass, ! 159: NULL, ! 160: NULL, ! 161: 0, ! 162: 0, ! 163: 0, ! 164: 0, ! 165: NULL, ! 166: HWND_TOP, ! 167: OBJECTID, ! 168: NULL, ! 169: NULL); ! 170: ! 171: if(hwndObject == NULL) { ! 172: WinPostMsg(hwndMain, TM_THREADINITFAILED, NULL, NULL); ! 173: ! 174: goto ExitBkThread; ! 175: } ! 176: ! 177: /* set thread created flag so another thread of this type ! 178: cannot be created */ ! 179: fThreadCreated = TRUE; ! 180: ! 181: /* clear initialization semaphore */ ! 182: DosPostEventSem(hevThreadInit); ! 183: ! 184: ! 185: /* message loop */ ! 186: while(WinGetMsg(hmqBkThread, (PQMSG)&qmsg, NULL, NULL, NULL)) ! 187: WinDispatchMsg(hmqBkThread, (PQMSG)&qmsg); ! 188: ! 189: ExitBkThread: ! 190: ! 191: /* destroy object window, clean up message queue and terminate */ ! 192: if(WinIsWindow(habBkThread, hwndObject)) ! 193: WinDestroyWindow(hwndObject); ! 194: ! 195: WinDestroyMsgQueue(hmqBkThread); ! 196: WinTerminate(habBkThread); ! 197: ! 198: /* If termination is due to an error initializing the thread, then ! 199: clear the initialization semaphore so that the main thread ! 200: can continue. */ ! 201: if(!fThreadCreated) ! 202: DosPostEventSem(hevThreadInit); ! 203: ! 204: ! 205: /*------------------------------------------------------------------* ! 206: * ! 207: * Note: C-runtime considerations: ! 208: * ! 209: * If you use non-reentrant C runtime functions in the second thread, ! 210: * then you should use call _endthread here instead of DosExit(). ! 211: * See the comment in the CreateBackgroundThread() routine for ! 212: * more information. ! 213: * ! 214: *------------------------------------------------------------------*/ ! 215: DosExit(EXIT_THREAD, NULL); ! 216: ! 217: /* the thread parameter is not currently used */ ! 218: ulThreadParam; ! 219: ! 220: } /* BackgroundThread() */ ! 221: ! 222: ! 223: /****************************************************************\ ! 224: * Creates the Background thread ! 225: *-------------------------------------------------------------- ! 226: * ! 227: * Name: CreateBackgroundThread() ! 228: * ! 229: * Purpose: Routine creates the background thread ! 230: * ! 231: * Usage: Routine is called at initialization time to create ! 232: * a background processing thread. ! 233: * ! 234: * Method: The routine calls DosCreateThread with the Background ! 235: * thread routine. ! 236: * ! 237: * Returns: TRUE if thread is created successfully, FALSE if not ! 238: * or if the thread was already created ! 239: * ! 240: \****************************************************************/ ! 241: BOOL CreateBackgroundThread(VOID) ! 242: { ! 243: SHORT sRet; ! 244: ! 245: /*------------------------------------------------------------------* ! 246: * ! 247: * Note: C-runtime considerations: ! 248: * ! 249: * If you use non-reentrant C runtime functions in the second thread, ! 250: * then you will need to use _beginthread and _endthread instead of ! 251: * DosCreateThread and DosExit. In addition, you will have ! 252: * to link with LIBCMT.LIB instead of LIBC.LIB, and you will ! 253: * have use -D_MT as a compiler option. ! 254: * ! 255: *------------------------------------------------------------------*/ ! 256: ! 257: ! 258: if(!fThreadCreated) { ! 259: DosCreateEventSem((PSZ)NULL, &hevThreadInit, 0L, FALSE); ! 260: sRet = DosCreateThread(&tidBkThread, ! 261: (PFNTHREAD)BackgroundThread, ! 262: 0L, ! 263: 0L, ! 264: THREADSTACKSIZE); ! 265: } else ! 266: return FALSE; ! 267: ! 268: /* wait until the thread has finished initialization */ ! 269: if(DosWaitEventSem(hevThreadInit, SEM_TIMEOUT)) ! 270: return FALSE; ! 271: ! 272: return((BOOL)(sRet == 0)); ! 273: ! 274: } /* CreateBackgroundThread() */ ! 275: ! 276: ! 277: /****************************************************************\ ! 278: * Destroys the Background thread ! 279: *-------------------------------------------------------------- ! 280: * ! 281: * Name: DestroyBackgroundThread() ! 282: * ! 283: * Purpose: Routine destroys the background thread ! 284: * ! 285: * Usage: Routine is called at exit time to destroy the background ! 286: * processing thread. ! 287: * ! 288: * Method: The routine posts a WM_CLOSE message to the object window ! 289: * to end its message loop. It then waits to make sure that the ! 290: * thread has been terminated before it returns. ! 291: * ! 292: * Returns: ! 293: * ! 294: \****************************************************************/ ! 295: VOID DestroyBackgroundThread(VOID) ! 296: { ! 297: ! 298: PostBkThreadMsg(WM_CLOSE, NULL, NULL); ! 299: ! 300: DosWaitThread(&tidBkThread, 0); ! 301: ! 302: } /* DestroyBackgroundThread() */ ! 303: ! 304: ! 305: /****************************************************************\ ! 306: * Posts a message to the Background thread ! 307: *-------------------------------------------------------------- ! 308: * ! 309: * Name: PostBkThreadMsg() ! 310: * ! 311: * Purpose: Routine posts a message to the object window of the ! 312: * background thread. ! 313: * ! 314: * Usage: Routine is called whenever a message is to be posted to ! 315: * the background processing thread. ! 316: * ! 317: * Method: The routine posts the message to the object window of the ! 318: * thread. ! 319: * ! 320: * Returns: the return value from WinPostMsg(). ! 321: * ! 322: \****************************************************************/ ! 323: BOOL PostBkThreadMsg(msg, mp1, mp2) ! 324: USHORT msg; /* message id */ ! 325: MPARAM mp1; /* first parameter */ ! 326: MPARAM mp2; /* second parameter */ ! 327: { ! 328: ! 329: return(WinPostMsg(hwndObject, msg, mp1, mp2)); ! 330: ! 331: } /* PostBkThreadMsg() */ ! 332: ! 333: ! 334: /****************************************************************\ ! 335: * Sends a message to the Background thread ! 336: *-------------------------------------------------------------- ! 337: * ! 338: * Name: SendBkThreadMsg() ! 339: * ! 340: * Purpose: Routine sends a message to the object window of the ! 341: * background thread. ! 342: * ! 343: * Usage: Routine is called whenever a message is to be sent to ! 344: * the background processing thread. ! 345: * ! 346: * Method: The routine sends the message to the object window of the ! 347: * thread. ! 348: * ! 349: * Returns: the return value from WinSendMsg(). ! 350: * ! 351: \****************************************************************/ ! 352: MRESULT SendBkThreadMsg(msg, mp1, mp2) ! 353: USHORT msg; /* message id */ ! 354: MPARAM mp1; /* first parameter */ ! 355: MPARAM mp2; /* second parameter */ ! 356: { ! 357: ! 358: return(WinSendMsg(hwndObject, msg, mp1, mp2)); ! 359: ! 360: } /* SendBkThreadMsg() */ ! 361: ! 362: ! 363: /****************************************************************\ ! 364: * Dialog procedure for the Object window ! 365: *-------------------------------------------------------------- ! 366: * ! 367: * Name: ObjectWndProc(hwnd, msg, mp1, mp2) ! 368: * ! 369: * Purpose: Processes all messages sent to the Object window ! 370: * ! 371: * Usage: Called for each message sent to the Object window. ! 372: * ! 373: * Method: the Object window processes the messages that tell ! 374: * the background thread what action to take. Since ! 375: * the object window is not visible, it will not ! 376: * process any of the standard window messages. ! 377: * ! 378: * Returns: Dependent upon message sent ! 379: * ! 380: \****************************************************************/ ! 381: MRESULT EXPENTRY ObjectWndProc(hwnd, msg, mp1, mp2) ! 382: HWND hwnd; /* handle of window */ ! 383: USHORT msg; /* id of message */ ! 384: MPARAM mp1; /* first message parameter */ ! 385: MPARAM mp2; /* second message parameter */ ! 386: { ! 387: ! 388: switch(msg) { ! 389: ! 390: /*--------------------------------------------------------------*\ ! 391: * Include any user defined messages to determine which ! 392: * action the background thread should take ! 393: \*--------------------------------------------------------------*/ ! 394: ! 395: default: ! 396: return (WinDefWindowProc(hwnd, msg, mp1, mp2)); ! 397: break; ! 398: } ! 399: ! 400: return 0L; ! 401: ! 402: hwnd; ! 403: mp1; ! 404: mp2; ! 405: ! 406: } /* ObjectWndProc() */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.