|
|
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.