home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
pwr16.zip
/
POWER.C
< prev
next >
Wrap
Text File
|
1994-11-07
|
34KB
|
648 lines
/*______________________________________________________________________
| PowerThread (c) 1994 Greg Ratajik |
|-----------------------------------------------------------------------|
| You may use this code in your programs under the |
| following conditions: |
| |
| o You keep this module seperate, with all comments |
| copyright notices intact (You can, of course add to |
| or change to fit your needs, I just ask that you |
| keep the main banners/info intact.) |
| |
| o If you sell a product that uses this, I ask that |
| you put my name and contact info in it, and what |
| you got out of it. (This doesn't need to be in a |
| about box, but it would be nice at the end of the |
| credits of the .INF file, or DOC's.) |
| |
| Beyond that, go for it! You're free to hack this up |
| in any way that you need. I'm not asking for any return|
| on this code, except (mabye?) to provide a quick and |
| easy way for fellow OS/2 developers to thread their |
| programs. |
| |
| --------------------------------------------------- |
| | Special Thanks to Ron Finlayson, for part of the | |
| | initial concept work on this. It really helps to | |
| | have someone to brain storm with! :) | |
| --------------------------------------------------- |
| |
| ***************************************************************** |
| *DISCLAIMER OF WARRANTIES. The following code is * |
| *sample code created by Greg Ratajik. The code is provided * |
| *"AS IS", without warranty of any kind. Greg Ratatjik shall not* |
| *be liable for any damages arising out of your use of the sample* |
| *code. * |
| ***************************************************************** |
| |
|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~|
| Description: This module has two main functions in it, PowerCall and |
| PowerHABCall. Both of them let an application call a |
| function, while processing a PM message, without locking|
| up PM. The function calls can be treated like normal |
| function that runs consecutively to other function calls|
| (instead of posting messages back to the parent, or |
| having a worker thread processing requests) |
| |
| The basic flow of this program is: |
| |
| PowerHABCall(): |
| |
| Get PM Message |
| | |
| \|/ |
| Start Thread -------------- |
| | | |
| | | |
| \|/ \|/ |
| Process Queue Call Function |
| | | |
| | | |
| \|/ \|/ |
| Return <---------- Notify Function Done |
| | |
| | |
| \|/ |
| Continue Processing |
| Message |
| |
| ======================================================= |
| |
| PowerCall(): |
| |
| Get PM Message |
| | |
| \|/ |
| Start Thread -------------- |
| | | |
| | | |
| \|/ \|/ |
| Start DLG Call Function |
| (Will process messages) | |
| | | |
| | | |
| \|/ \|/ |
| Return <---------- Post Message To DLG |
| | |
| | |
| \|/ |
| Continue Processing |
| Message |
| |
| |
| PowerHABCall is the most staight forward way, but you |
| have to pass the HAB. PowerCall is a little more |
| complex, but if you want to display somthing to the user|
| while the thread is running (i.e. do a timer,and animate|
| the pointer while the thread is running...) or if you |
| don't want to worry about getting the HAB, use |
| it. |
| |
| For more information, and some thoughts on how to use |
| this technique, see POWER.DOC |
| |
| If you have any questions and comments about this |
| technique, you can get in touch with me at: |
| |
| CompuServe : 74555,542 |
| Internet : 74555.542@compuserve.com |
| Voice : (305)/340-7985 |
| OS/2 ShareWare BBS : (703)/385-4325 |
| |
| Version Date Change |
| ------------ --------- ---------------------------------------- |
| 1.00 09-01-1994 Initial Development |
|_____________________________________________________________________*/
#define INCL_PM /* PM Support */
#define INCL_DOSPROCESS /* Process and thread support */
/*______________________________________________________________________
| |
| System Includes |
|_____________________________________________________________________*/
#define _MT
#include <os2.h> /* Base OS/2 Include */
#include <stdlib.h> /* malloc and free */
#include <process.h> /* _beginthread support */
/*______________________________________________________________________
| |
| Application Specific Includes & Defines |
|_____________________________________________________________________*/
#include "power.h" /* Prototypes for PowerCalls */
#include "test.rch" /* RC info for the DLG */
/*______________________________________________________________________
| |
| Gobal Local Variables |
|_____________________________________________________________________*/
#define STACK_SIZE 15000
BOOL g_bDone = FALSE; /* Used to tell message loop that thread is done */
/*______________________________________________________________________
| |
| Gobal Local Structures |
|_____________________________________________________________________*/
/*____________________________________
| |
| pfnFunctionAddr and hWnd |
| should be kept in the structure. |
| pUserParm should be whatever parm |
| needs to be passed to the user |
| function. Any number of user parms |
| can be added, but you must modify |
| the functions that use the structure|
|____________________________________*/
/*____________________________________
| |
| The primary use of this structure |
| is to isolate the information that |
| needs to be passed to the thread. |
| (You can only pass ONE parm to a |
| thread) If you don't want to use a |
| structure, you can use globals. |
|____________________________________*/
typedef struct _THREAD_CALL_INFO /* Process Linkage Structure */
{
void far *pfnFunctionAddr; /* Address of Function to call */
HWND hWnd; /* HWND of processing DLG. */
PVOID pUserParm; /* User parm(s)... */
} THREAD_CALL_INFO, *PTHREAD_CALL_INFO;
/*____________________________________________________________________
| |
| Function Prototypes. |
|____________________________________________________________________*/
MRESULT EXPENTRY PowerCallWndProc (HWND hWndDlg, USHORT ulMsg, MPARAM mp1, MPARAM mp2);
MRESULT EXPENTRY FrameWindowMsgProc(HWND hWndDlg, USHORT ulMsg, MPARAM mp1, MPARAM mp2);
VOID CallFunction ( PTHREAD_CALL_INFO); /* Loader for PowerCall */
VOID CallHABFunction ( PTHREAD_CALL_INFO); /* Loader for PowerHABCall */
/*__________________________________________________________________________
| |
| Function: PowerHABCall |
| |
| Description: This function calls the passed function with the passed parm,|
| and then processes the message queue until the thread is done|
| |
| The result is that you can make the call to your function, |
| and wait for it to return, without locking PM up. |
| |
| This is Solution #1, which requires that HAB is passed. |
| It should be possible to either have HAB as a global, or |
| to ask the system what the HAB is for the process. |
| |
| Return: BOOL - You can use the structure to pass back your own |
| return value. See CallHABFunction for more info. |
| |
| -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| C H A N G E L O G |
| -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| |
| PRG. DATE DESCRIPTION |
| ---- ---------- --------------------------------------------------- |
| RATAJIK 11-01-1994 Initial Developement |
|__________________________________________________________________________*/
BOOL PowerHABCall(HAB hAB ,
PFN pfnFunctionAddr,
PVOID pUserParm )
{
PTHREAD_CALL_INFO ptciData = malloc(sizeof(THREAD_CALL_INFO));
QMSG qmsg;
INT pid;
/*____________________________________
| |
| Copy the call info to the comm. |
| structure. |
|____________________________________*/
ptciData->pfnFunctionAddr = (void far *)pfnFunctionAddr;
ptciData->pUserParm = pUserParm;
g_bDone = FALSE;
/*____________________________________
| |
| Start the Loader thread. It will |
| call the function passed in |
| pfnFunctionAddr. |
|____________________________________*/
pid=_beginthread(CallHABFunction, /* Address of the Loader Function */
NULL, /* Use the programs stack */
STACK_SIZE, /* Amount of the stack we want to use */
(PVOID)ptciData); /* Info for the Loader Function */
/*____________________________________
| |
| Process messages until g_bDone is |
| TRUE. This, in effect, prevents PM |
| from locking up while we process the|
| message that called this function. |
|____________________________________*/
while(WinGetMsg(hAB, (PQMSG)&qmsg, (HWND)NULL, 0, 0) && !g_bDone)
WinDispatchMsg(hAB, (PQMSG)&qmsg);
/*____________________________________
| |
| Free up the Data, and return. If |
| you want to return with another |
| type/value, you can use the comm |
| structure to pass it. |
|____________________________________*/
free(ptciData);
return(TRUE);
}
/*__________________________________________________________________________
| |
| Function: CallHABunction |
| |
| Description: This function is used to call the user function, with any |
| parms needed. When it is done, it will set g_bDone to TRUE, |
| which will tell the message processing loop to finish. If you|
| don't want to use a global, you can use another BOOL in the |
| passed structure, or a semaphore. |
| |
| Return: VOID |
| |
| -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| C H A N G E L O G |
| -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| |
| PRG. DATE DESCRIPTION |
| ---- ---------- --------------------------------------------------- |
| RATAJIK 11-01-1994 Initial Developement |
|__________________________________________________________________________*/
VOID CallHABFunction(PTHREAD_CALL_INFO ptciData)
{
PFN pfnAddr;
/*____________________________________
| |
| Resolve the function address. |
| |
|____________________________________*/
pfnAddr = (PFN) ptciData->pfnFunctionAddr;
/*____________________________________
| |
| Call the function with the parm list|
| Add vars to the parm list as needed.|
|____________________________________*/
pfnAddr(ptciData->pUserParm);
/*____________________________________
| |
| Tell the while loop for the queue |
| that we are done. |
|____________________________________*/
g_bDone = TRUE;
}
/*__________________________________________________________________________
| |
| Function: PowerCall |
| |
| Description: This function calls the passed function with the passed parm.|
| It will then do a WinDlgBox. This will process any message |
| untill the thread is done. The WinDlgBox can also be used to|
| display a message to the user, while the thead is processing.|
| |
| Return: BOOL - You can use the structure to pass back your own |
| return value. See CallHABFunction for more info. |
| |
| -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| C H A N G E L O G |
| -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| |
| PRG. DATE DESCRIPTION |
| ---- ---------- --------------------------------------------------- |
| RATAJIK 11-01-1994 Initial Developement |
|__________________________________________________________________________*/
BOOL PowerCall(PFN pfnFunctionAddr,
PVOID pUserParm )
{
PTHREAD_CALL_INFO ptciData = malloc(sizeof(THREAD_CALL_INFO));
INT pid;
/*____________________________________
| |
| Copy the call info to the comm. |
| structure. |
|____________________________________*/
ptciData->pfnFunctionAddr = (void far *)pfnFunctionAddr;
ptciData->pUserParm = pUserParm;
ptciData->hWnd = NULL; /* The DLG will fill this out for us */
/*____________________________________
| |
| Start up the Loader thread. It will|
| call the function passed in |
| pfnFunctionAddr |
|____________________________________*/
pid=_beginthread(CallFunction, /* Address of the Loader Function */
NULL, /* Use the programs stack */
STACK_SIZE, /* Amount of the stack we want to use */
(PVOID)ptciData); /* Info for the Loader Function */
/*____________________________________
| |
| Run the DLG. This has the same |
| results as the message loop in |
| PowerHABCall. |
| |
| It will return when the thread posts|
| a message to it. |
| |
| You could also do a WinCreateWindow,|
| and process message, but this way |
| you can show somthing to the user. |
|____________________________________*/
WinDlgBox(HWND_DESKTOP,
HWND_DESKTOP,
PowerCallWndProc,
0,
DLG_THREAD,
(PVOID)ptciData); /* Pass this so DLG can get to hwnd */
/*____________________________________
| |
| Free up the Data, and return. If |
| you want to return with another |
| type/value, you can use the comm |
| structure to pass it. |
|____________________________________*/
free(ptciData);
return(TRUE);
}
/*__________________________________________________________________________
| |
| Function: CallFunction |
| |
| Description: This function is used to call the user function, with any |
| parms needed. When it is done, it will post a message back |
| to the DLG to let it know it should dismiss itself. |
| |
| Return: VOID |
| |
| -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| C H A N G E L O G |
| -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| |
| PRG. DATE DESCRIPTION |
| ---- ---------- --------------------------------------------------- |
| RATAJIK 11-01-1994 Initial Developement |
|__________________________________________________________________________*/
VOID CallFunction(PTHREAD_CALL_INFO ptciData)
{
PFN pfnAddr;
/*____________________________________
| |
| Resolve the function address. |
| |
|____________________________________*/
pfnAddr = (PFN)ptciData->pfnFunctionAddr;
/*____________________________________
| |
| Call the function with the parm list|
| Add vars to the parm list as needed.|
|____________________________________*/
pfnAddr(ptciData->pUserParm);
/*____________________________________
| |
| Tell the DLG that we are done. |
| |
|____________________________________*/
if(ptciData->hWnd)
WinPostMsg(ptciData->hWnd, WM_INITDLG, (MPARAM)7985, 0);
}
/*__________________________________________________________________________
| |
| Function: PowerCallWndProc |
| |
| Description: This function acts as a message processor for the message |
| queue. When the thread is done, it will post a message to |
| this DLG, which will cause the DLG to finish. |
| |
| A semaphore might work better here, as it's possible the |
| thread could finish before the DLG started. I've never |
| had it happen yet, as beginthread general takes a while to |
| start up. |
| |
| Return: MRESULT |
| |
| -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| C H A N G E L O G |
| -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| |
| PRG. DATE DESCRIPTION |
| ---- ---------- --------------------------------------------------- |
| RATAJIK 11-01-1994 Initial Developement |
|__________________________________________________________________________*/
MRESULT EXPENTRY PowerCallWndProc(HWND hWndDlg, USHORT msg,MPARAM mp1, MPARAM mp2)
{
static PTHREAD_CALL_INFO ptciData;
switch (msg)
{
/*____________________________________
| |
| I'm using WM_INITDLG and 7985 to |
| make this very simple. You can add |
| your own message ID's if you like. |
|____________________________________*/
case WM_INITDLG:
{
/*____________________________________
| |
| The thread will post this message to|
| us when it is done |
|____________________________________*/
if(mp1 == (MPARAM)7985)
{
WinDismissDlg(hWndDlg, TRUE);
}
else
{
/*____________________________________
| |
| mp2 will contain the comm structure.|
| Put the current HWND in to it, so |
| the thread will know where to post |
| the "finished" message. |
|____________________________________*/
ptciData = (MPARAM)mp2;
ptciData->hWnd = hWndDlg;
/*____________________________________
| |
| Provide the Running/Wait animation. |
| |
|____________________________________*/
WinSubclassWindow(WinWindowFromID(hWndDlg, FRAME_WAIT), FrameWindowMsgProc);
WinSendMsg( WinWindowFromID(hWndDlg, FRAME_WAIT),
WM_CREATE,
0, 0);
/*____________________________________
| |
| If you don't want the DLG to display|
| info to the user, do this (Makes |
| the DLG invisible) |
|____________________________________*/
//WinSetWindowPos(hWndDlg, 0,
// 0, 0, 0, 0, SWP_HIDE|SWP_MOVE|SWP_SIZE );
}
}
break;
default:
return(WinDefDlgProc(hWndDlg, msg, mp1, mp2));
break;
}
return(FALSE);
}
/*__________________________________________________________________________
| |
| Function: FrameWindowMsgProc |
| |
| Description: This function does a little animation in a frame. It will |
| cycle through the array of bitmaps. You can replace these |
| bitmaps with anything you like. You may note that the |
| this takes a fair amount of CPU time. If you want to |
| lessen the amount of CPU activity used for the animation, |
| you can slow it down by increasing the WinStartTimer value. |
| |
| (This was a last minute hack to show what you could do |
| using the DLG version of PowerCall. Feel free to improve |
| it...) |
| |
| Return: MRESULT |
| |
| -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| C H A N G E L O G |
| -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| |
| PRG. DATE DESCRIPTION |
| ---- ---------- --------------------------------------------------- |
| RATAJIK 11-05-1994 Initial Developement |
|__________________________________________________________________________*/
MRESULT EXPENTRY FrameWindowMsgProc(HWND hWndDlg, USHORT ulMsg, MPARAM mp1, MPARAM mp2)
{
static HBITMAP hbBMP[BMP_RUN10]; /* Array of Bitmaps to display */
static SHORT sCur = 0; /* Current Bitmap to display */
static SHORT sDir = 1; /* Move foward or backwards in the array */
static BOOL bFirst = TRUE;
INT j;
HPS hPS;
RECTL rClient;
/*_________________________________________
| |
| Process messages from subclassed field. |
|_________________________________________*/
switch(ulMsg)
{
case WM_CREATE:
/*____________________________________
| |
| We want to start moving foward in |
| the array. |
|____________________________________*/
sCur = -1;
sDir = 1;
/*____________________________________
| |
| The timer is used to force a re- |
| paint the window ever x ms. The |
| actual calculations will be in |
| WM_PAINT |
|____________________________________*/
WinStartTimer(0, hWndDlg, 0, 150);
break;
case WM_TIMER:
/*____________________________________
| |
| This will generate a WM_PAINT |
| |
|____________________________________*/
WinInvalidateRect(hWndDlg, NULL, TRUE);
break;
case WM_PAINT:
/*____________________________________
| |
| Get ready to paint.. |
| |
|____________________________________*/
hPS = WinBeginPaint(hWndDlg, 0, 0);
GpiSetBackColor(hPS, CLR_YELLOW);
if(bFirst)
{
bFirst = FALSE;
/*____________________________________
| |
| Load the bitmaps into the array. |
| |
|____________________________________*/
for(j = BMP_RUN1; j < BMP_RUN10; j++)
{
hbBMP[j-BMP_RUN1] = GpiLoadBitmap(hPS, 0, j, 0, 0);
}
}
/*____________________________________
| |
| Move the current index in the |
| current direction. |
|____________________________________*/
sCur += sDir;
/*____________________________________
| |
| If we've gone beyond a boundry, |
| start moving in the next direction. |
|____________________________________*/
if(sCur >= (BMP_RUN10 - BMP_RUN1))
sDir = -1;
if(sCur <= 0)
sDir = 1;
WinQueryWindowRect(hWndDlg, &rClient);
/*____________________________________
| |
| Display the bitmap, stretching to |
| the frame. |
|____________________________________*/
WinDrawBitmap(hPS, hbBMP[sCur], NULL, (POINTL *)&rClient, (LONG)1, (LONG)2, DBM_IMAGEATTRS|DBM_STRETCH);
WinEndPaint(hPS);
break; /* End of WM_PAINT */
}
return WinDefDlgProc(hWndDlg, ulMsg, mp1, mp2);
}