|
|
Microsoft OS/2 SDK PM 02-24-1989
/***********************************************************************\
* spyhook.c - Spy global input hook interface library
* Created by Microsoft Corporation, 1989
*
* This dynlink is needed because global input hooks must reside in a DLL.
\***********************************************************************/
#define INCL_DOSPROCESS
#define INCL_WINHEAP
#define INCL_WINHOOKS
#define INCL_WINWINDOWMGR
#include <os2.h>
#include "spyhook.h"
ULONG spyhookSem = 0L; /* global semaphore for this module */
HMODULE hmodSpy; /* dynlink module handle */
SHORT SpybHooks; /* Which hook do we use? */
HAB habOwner = (HAB)0; /* Hook owner's anchor block */
HMQ hmqOwner = (HMQ)0; /* Hook owner's message queue */
BOOL fRecording = FALSE; /* Are we recording now? */
BOOL fAnythingToWatch = FALSE; /* Is there anything to watch? */
BOOL fDispMsgsNotInList = TRUE; /* Disp msgs not in list? */
/* Define array of window handles that we are going to process */
BOOL fProcessAllFrames = FALSE; /* Are we processing all frame messages?*/
BOOL fProcessAllWindows = FALSE;/* Are we processing all windows?*/
HWND *pahwndSpy = NULL; /* Array of hwnds to spy on, no max here */
int chwndSpy = 0; /* Max windows to spy */
/* Define array of HMQ's to spy on */
HMQ *pahmqSpy = NULL; /* HMQ list to spy on */
int chmqSpy = 0; /* Count of hmqs we are spying on */
/* Define message filter array */
UCHAR rgMessageFilter[MAXMSGFILTERBYTES] = "";
UCHAR GMsgEnableAndType(USHORT); /* Is message in message list?*/
VOID GrabMsgDataWords(SHORT, UCHAR); /* Get extra words for message */
VOID CopyStruct(UCHAR FAR *pbSrc, UCHAR FAR *pbDst, SHORT cb);/* Copy bytes */
/* Define an array of messages to pass to whomever calls us */
ULONG spyMsgSem = 0L; /* global semaphore for this module */
QMSGSPY rgqmsgSpy[MAXMSGCNT]; /* Array of messages to process */
SHORT cmsgSpy = 0; /* Count of messages yet to be read */
SHORT imsgWrite = 0; /* Index to message to write out */
SHORT imsgRead = 0; /* Index to message to read */
HHEAP hheapSpyHook; /* Heap for SpyHook DLL */
SHORT acbMPTypes[MP_MASK+1] = { /* Number of desired bytes to extract */
0, /* Normal fields, no pointers */
sizeof(SWP), /* MPT_SWP */
sizeof(RECTL), /* MPT_RECTL */
0, /* MPT_WNDPRMS we don't process yet */
sizeof(QMSG) /* MPT_QMSG */
};
/* Information for getting selector information in different PID context */
PID pidLNSpy = 0xffff; /* Which process */
USHORT selectorLNSpy = 0; /* Which Selector */
WHOISINFO whoIsLNSpy; /* Symbol information */
int rcLNSpy = -1; /* Return code */
/* Define all external functions */
extern VOID BuildStackTrace(CHAR FAR *, SHORT, SHORT);
/* Define all function prototypes */
VOID SpyCheckPIDForSymbol(VOID);
BOOL FAR PASCAL SpyInputHook(HAB, PQMSG, USHORT);
BOOL FAR PASCAL SpySendMsgHook(HAB, PSMHSTRUCT, USHORT);
VOID PASCAL Init(HMODULE);
/***********************************************************************\
* BOOL FAR PASCAL SpyInputHook( hab, lpqmsg, fs )
* HAB hab;
* PQMSG lpqmsg;
* USHORT fs;
*
* Effect: This is the global input hook procedure. Note that hook
* procedures can be chained, so we always return FALSE to pass the
* message to the next guy in the chain.
*
* Return value: FALSE to pass message to next hook procedure.
\***********************************************************************/
BOOL FAR PASCAL SpyInputHook( hab, lpqmsg, fs )
HAB hab;
PQMSG lpqmsg;
USHORT fs;
{
UCHAR bMPType;
/*
* Check first to see if we are looking for a process's symbols
*/
if (pidLNSpy != 0xffff)
SpyCheckPIDForSymbol();
/*
* First check to see if we are processing any hook messages
*/
if (!fRecording || !fAnythingToWatch || (cmsgSpy >= MAXMSGCNT))
return (FALSE); /* No, let the next one have it now */
/*
* See if we have any messages to process - re-check to make sure we
* don't overwrite our queue.
*/
if (DosSemRequest((HSEM)(PULONG)&spyhookSem, 100L) != 0)
return (FALSE);
if (cmsgSpy < MAXMSGCNT) {
if (SpyFWindowInList(lpqmsg->hwnd, FALSE) &&
(bMPType = GMsgEnableAndType(lpqmsg->msg))) {
rgqmsgSpy[imsgWrite].fs = fs; /* Save the flags */
rgqmsgSpy[imsgWrite].qmsg = *lpqmsg; /* Save the message */
GrabMsgDataWords(imsgWrite, bMPType);
imsgWrite++;
if (imsgWrite == MAXMSGCNT)
imsgWrite = 0; /* Wrap around */
cmsgSpy++;
DosSemClear((HSEM)(PULONG)&spyMsgSem);
}
}
DosSemClear( (HSEM)(PULONG)&spyhookSem );
return FALSE; /* Let system take normal action */
}
/***********************************************************************\
* BOOL FAR PASCAL SpySendMsgHook( hab, lpsmh, fInterTask )
* HAB hab;
* PSMHSTRUCT lpsmh;
* BOOL fInterTask;
*
* Effect: This is the global input hook procedure. Note that hook
* procedures can be chained, so we always return FALSE to pass the
* message to the next guy in the chain.
*
* Return value: FALSE to pass message to next hook procedure.
\***********************************************************************/
BOOL FAR PASCAL SpySendMsgHook( hab, lpsmh, fInterTask )
HAB hab;
PSMHSTRUCT lpsmh;
BOOL fInterTask;
{
UCHAR bMPType;
PIDINFO pidinfo;
/*
* Check first to see if we are looking for a process's symbols
*/
if (pidLNSpy != 0xffff)
SpyCheckPIDForSymbol();
/*
* First check to see if we are processing any hook messages
*/
if (!fRecording || !fAnythingToWatch || (cmsgSpy >= MAXMSGCNT))
return (FALSE); /* No, let the next one have it now */
/*
* See if we have any messages to process
*/
if (DosSemRequest((HSEM)(PULONG)&spyhookSem, 100L) != 0)
return (FALSE);
/* Make sure no one got in by mistake */
if (cmsgSpy < MAXMSGCNT) {
if (SpyFWindowInList(lpsmh->hwnd, FALSE) &&
(bMPType = GMsgEnableAndType(lpsmh->msg))) {
/*
* Store out message, must move pieces separately
*/
rgqmsgSpy[imsgWrite].fs = fInterTask;
rgqmsgSpy[imsgWrite].qmsg.hwnd = lpsmh->hwnd;
rgqmsgSpy[imsgWrite].qmsg.msg = lpsmh->msg;
rgqmsgSpy[imsgWrite].qmsg.mp1 = lpsmh->mp1;
rgqmsgSpy[imsgWrite].qmsg.mp2 = lpsmh->mp2;
rgqmsgSpy[imsgWrite].qmsg.time = (ULONG)-1;
rgqmsgSpy[imsgWrite].qmsg.ptl.x = 0;
rgqmsgSpy[imsgWrite].qmsg.ptl.y = 0;
GrabMsgDataWords(imsgWrite, bMPType);
/* Now get the PID/TID info, and do the stack backtrace */
DosGetPID(&pidinfo);
rgqmsgSpy[imsgWrite].pidSend = pidinfo.pid;
rgqmsgSpy[imsgWrite].tidSend = pidinfo.tid;
BuildStackTrace((CHAR FAR *)rgqmsgSpy[imsgWrite].pvoidStack,
CALLSTOSKIP, MAXSTRACE);
imsgWrite++;
if (imsgWrite == MAXMSGCNT)
imsgWrite = 0; /* Wrap around */
cmsgSpy++;
DosSemClear((HSEM)(PULONG)&spyMsgSem);
}
}
DosSemClear( (HSEM)(PULONG)&spyhookSem );
return FALSE; /* Let system take normal action */
}
/***********************************************************************\
* BOOL FAR PASCAL SpyInstallHook( hab, hmq, fSendMessage, bHooks)
*
* Effect: This routine installs a system-wide HK_INPUT hook. The hab
* hmq are remembered for message posting. Note that we only allow
* one input hook to be installed through this routine, but other
* apps may call WinSetHook directly.
*
* Returns value: TRUE if hook installed successfully, FALSE otherwise.
\***********************************************************************/
BOOL FAR PASCAL SpyInstallHook( hab, hmq, bHooks )
HAB hab;
HMQ hmq;
USHORT bHooks;
{
BOOL fRet;
SEL selHeap;
DosSemRequest( (HSEM)(PULONG)&spyhookSem, -1L);
/*
* If this is the first time through, we need to create a local heap
* to store message information.
*/
if (hheapSpyHook == NULL) {
selHeap = (SEL)(((ULONG)((PSZ)&hheapSpyHook)) >> 16);
hheapSpyHook = WinCreateHeap(selHeap, 1024, 0, 0, 100,
HM_MOVEABLE | HM_VALIDSIZE);
if (hheapSpyHook == NULL)
return (FALSE);
}
/*
* Look at hook index.
*
* if it equals HK_INPUT then
* install a system-wide input hook
* else
* set system wide SENDMSG hook
*/
SpybHooks = bHooks;
if (SpybHooks & SPYH_INPUT)
fRet = WinSetHook( hab, (HMQ)0, HK_INPUT, (PFN)SpyInputHook,
hmodSpy );
if (SpybHooks & SPYH_SENDMSG)
fRet = WinSetHook( hab, (HMQ)0, HK_SENDMSG, (PFN)SpySendMsgHook,
hmodSpy );
if (fRet) {
habOwner = hab;
hmqOwner = hmq;
}
DosSemSet((HSEM)(PULONG)&spyMsgSem); /* Init, no messages avail */
DosSemClear( (HSEM)(PULONG)&spyhookSem );
return fRet;
}
/***********************************************************************\
* BOOL FAR PASCAL SpySetWindowList( chwnd, rghwnd)
*
* Effect: This routine sets the list of window that we are interested
* in watching the messages for.
*
* Returns value: TRUE
\***********************************************************************/
BOOL FAR PASCAL SpySetWindowList( chwnd, rghwnd )
SHORT chwnd;
HWND FAR *rghwnd;
{
SHORT i;
HWND *phwndT;
DosSemRequest( (HSEM)(PULONG)&spyhookSem, -1L);
if (pahwndSpy) {
WinFreeMem(hheapSpyHook, (char *)pahwndSpy, sizeof(HWND) * chwndSpy);
pahwndSpy = NULL;
}
chwndSpy = chwnd;
if (chwndSpy > 0 ) {
phwndT = pahwndSpy = WinAllocMem(hheapSpyHook,
sizeof(HWND) * chwndSpy);
if (phwndT != NULL) {
for (i=0; i < chwnd; i++) {
*phwndT++ = *rghwnd++;
}
} else
chwndSpy = 0;
}
fAnythingToWatch = (chwndSpy > 0) || (chmqSpy > 0) ||
fProcessAllWindows || fProcessAllFrames;
DosSemClear( (HSEM)(PULONG)&spyhookSem );
return(TRUE);
}
/***********************************************************************\
* BOOL FAR PASCAL SpyGetWindowList( chwnd, rghwnd)
*
* Effect: This routine sets the list of window that we are interested
* in watching the messages for.
*
* Returns value: TRUE
\***********************************************************************/
SHORT FAR PASCAL SpyGetWindowList( chwnd, rghwnd )
SHORT chwnd;
HWND FAR *rghwnd;
{
SHORT i;
HWND *phwndT;
DosSemRequest( (HSEM)(PULONG)&spyhookSem, -1L);
if (chwnd > chwndSpy)
chwnd = chwndSpy;
phwndT = pahwndSpy;
for (i=0; i < chwnd; i++) {
*rghwnd++ = *pahwndSpy++;
}
DosSemClear( (HSEM)(PULONG)&spyhookSem );
return(chwnd);
}
/***********************************************************************\
* BOOL FAR PASCAL SpySetQueueList( chmq, rghmq )
*
* Effect: This routine sets the list of queues whose messages we watch.
*
* Returns value: TRUE
\***********************************************************************/
BOOL FAR PASCAL SpySetQueueList( chmq, rghmq )
SHORT chmq;
HMQ FAR *rghmq;
{
SHORT i;
HMQ *phmqT;
DosSemRequest( (HSEM)(PULONG)&spyhookSem, -1L);
/*
* If we previously had a list of HMQs to spy on, free the old list
* now
*/
if (pahmqSpy != NULL) {
WinFreeMem(hheapSpyHook, (char *)pahmqSpy, sizeof(HMQ) * chmqSpy);
pahmqSpy = NULL;
}
chmqSpy = chmq;
if (chmqSpy > 0) {
phmqT = pahmqSpy = WinAllocMem(hheapSpyHook, sizeof(HMQ) * chmqSpy);
if (phmqT != NULL) {
for (i=0; i < chmq; i++) {
*phmqT++ = *rghmq++;
}
} else
chmqSpy = 0;
}
fAnythingToWatch = (chwndSpy > 0) || (chmqSpy > 0) ||
fProcessAllWindows || fProcessAllFrames;
DosSemClear( (HSEM)(PULONG)&spyhookSem );
return(TRUE);
}
/***********************************************************************\
* BOOL FAR PASCAL SpyGetQueueList( chmq, rghmq )
*
* Effect: This routine gets the list of queues whose messages we watch.
*
* Returns value: TRUE
\***********************************************************************/
SHORT FAR PASCAL SpyGetQueueList( chmq, rghmq )
SHORT chmq;
HMQ FAR *rghmq;
{
SHORT i;
HMQ *phmqT;
DosSemRequest( (HSEM)(PULONG)&spyhookSem, -1L);
if (chmq > chmqSpy)
chmq = chmqSpy;
phmqT = pahmqSpy;
for (i=0; i < chmq; i++) {
*rghmq++ = *phmqT++;
}
DosSemClear( (HSEM)(PULONG)&spyhookSem );
return(chmq);
}
/***********************************************************************\
* BOOL FAR PASCAL SpySetMessageList(UCHAR FAR *prgNewMsgFilter,
* BOOL fNewDispMsgsNotInList)
*
* Effect: This routine sets the list of windows that whose message we watch.
*
* Returns value: TRUE
\***********************************************************************/
BOOL FAR PASCAL SpySetMessageList(prgNewMsgFilter, fNewDispMsgsNotInList)
UCHAR FAR *prgNewMsgFilter;
BOOL fNewDispMsgsNotInList;
{
SHORT i;
unsigned char *prgb;
DosSemRequest( (HSEM)(PULONG)&spyhookSem, -1L);
prgb = rgMessageFilter;
fDispMsgsNotInList = fNewDispMsgsNotInList;
for (i=0; i < MAXMSGFILTERBYTES; i++) {
*prgb++ = *prgNewMsgFilter++;
}
DosSemClear( (HSEM)(PULONG)&spyhookSem );
return(TRUE);
}
/***********************************************************************\
* BOOL FAR PASCAL SpyFWindowInList (hwnd, fInWindowListOnly)
*
* Effect: This function checks our current list of windows, and returns
* TRUE if the window is in the list, else returns FALSE.
*
* Returns value: TRUE if window is in list. Also, if we are in the special
* state we will pass through all frame windows.
\***********************************************************************/
BOOL FAR PASCAL SpyFWindowInList (hwnd, fInWindowListOnly)
register HWND hwnd;
BOOL fInWindowListOnly;
{
register int i;
char szClassName[10]; /* Class name of window */
CLASSINFO classinfo; /* Information about class */
HMQ hmqWindow; /* HMQ of window */
HMQ *phmqT; /* Temporary pointer in hmq list */
HWND *phwndT; /* Temporary pointer to HWND list */
phwndT = pahwndSpy;
for (i=0; i < chwndSpy; i++) {
if (hwnd == *phwndT++)
return (TRUE);
}
/* See if we are restricting to only windows in list */
if (fInWindowListOnly)
return (FALSE);
if (fProcessAllWindows)
return (TRUE); /* All windows pass through */
/*
* See if we are watching any message queues
*/
if (phmqT = pahmqSpy) {
hmqWindow = (HMQ)WinQueryWindowULong(hwnd, QWL_HMQ);
for (i=0; i < chmqSpy; i++) {
if (*phmqT++ == hmqWindow)
return (TRUE);
}
}
if (fProcessAllFrames) {
/* See if frame class */
if (hwnd == NULL)
return (TRUE); /* pass queue messages through */
WinQueryClassName(hwnd, sizeof(szClassName),
(PSZ)szClassName);
WinQueryClassInfo((HAB)NULL, (PSZ)szClassName,
&classinfo);
if (classinfo.flClassStyle & CS_FRAME)
return (TRUE);
}
return (FALSE);
}
/***********************************************************************\
* BOOL FAR PASCAL SpyReleaseHook(fZeroQueue)
*
* Effect: This routine releases the input hook, if it is installed.
*
* Returns value: TRUE if hook is released, FALSE otherwise.
\***********************************************************************/
BOOL FAR PASCAL SpyReleaseHook(fZeroQueue)
BOOL fZeroQueue;
{
BOOL fRet;
DosSemRequest ( (HSEM)(PULONG)&spyhookSem, -1L );
if ( habOwner ) {
if (SpybHooks & SPYH_INPUT)
fRet = WinReleaseHook( habOwner, (HMQ)0, HK_INPUT,
(PFN)SpyInputHook, hmodSpy );
if (SpybHooks & SPYH_SENDMSG)
fRet = WinReleaseHook( habOwner, (HMQ)0, HK_SENDMSG,
(PFN)SpySendMsgHook, hmodSpy );
if ( fRet ) {
habOwner = (HAB)0;
hmqOwner = (HMQ)0;
}
}
/*
* When the hook is freed, we want to clear message count out,
* make sure any process waiting will abort
* Only do this if the Zeroqueu flag was passed
*/
if (fZeroQueue) {
cmsgSpy = 0;
imsgWrite = 0;
imsgRead = 0;
if (pahwndSpy != NULL)
WinFreeMem(hheapSpyHook, (char *)pahwndSpy,
sizeof(HWND) * chwndSpy);
pahwndSpy = NULL;
chwndSpy = 0; /* Max windows to spy */
fRecording = FALSE; /* Set recording to off */
if (pahmqSpy != NULL)
WinFreeMem(hheapSpyHook, (char *)pahmqSpy, sizeof(HMQ) * chmqSpy);
pahmqSpy = NULL;
chmqSpy = 0;
fAnythingToWatch = FALSE;
DosSemClear((HSEM)(PULONG)&spyMsgSem); /* Free any process */
}
DosSemClear((HSEM)(PULONG)&spyhookSem);
return fRet;
}
/***********************************************************************\
* BOOL FAR PASCAL SpyHookOnOrOff( fOn)
*
* Effect: This routine allows the application to turn the hook
* processing on or off.
*
* Returns: TRUE
\***********************************************************************/
BOOL FAR PASCAL SpyHookOnOrOff(fOn)
BOOL fOn;
{
DosSemRequest ( (HSEM)(PULONG)&spyhookSem, -1L);
fRecording = fOn;
DosSemClear( (HSEM)(PULONG)&spyhookSem );
return (TRUE);
}
/***********************************************************************\
* BOOL FAR PASCAL SpySetAllFrameOpt(fAllFrames)
*
* Effect: Special state if TRUE will cause the window filter to pass
* all frame windows through. This is useful when debugging
* interactions between frame windows, when the windows are
* net yet created.
*
* Returns: TRUE
\***********************************************************************/
BOOL FAR PASCAL SpySetAllFrameOpt(fAllFrames)
BOOL fAllFrames;
{
fProcessAllFrames = fAllFrames;
fAnythingToWatch = (chwndSpy > 0) || (chmqSpy > 0) ||
fProcessAllWindows || fProcessAllFrames;
return (TRUE);
}
/***********************************************************************\
* BOOL FAR PASCAL SpySetAllWindowOpt(fAllWindows)
*
* Effect: Special state if TRUE will cause the window filter to pass
* all windows through. This is useful when debugging
* interactions between all of the windows.
*
* Returns: TRUE
\***********************************************************************/
BOOL FAR PASCAL SpySetAllWindowOpt(fAllWindows)
BOOL fAllWindows;
{
fProcessAllWindows = fAllWindows;
fAnythingToWatch = (chwndSpy > 0) || (chmqSpy > 0) ||
fProcessAllWindows || fProcessAllFrames;
return (TRUE);
}
/***********************************************************************\
* BOOL FAR PASCAL SpySetLNSymbolPID(PID pid, SELECTOR sel);
*
*
* Effect: Tell the hook to be on the lookout for a specific PID.
* If found running in the context of the specified process, we
* will get the selector information for the specified selector.
\***********************************************************************/
BOOL FAR PASCAL SpySetLNSymbolPID(pid, selector)
PID pid;
USHORT selector;
{
if (pidLNSpy == 0xffff) {
selectorLNSpy = selector;
rcLNSpy = -1; /* Assume error for now */
pidLNSpy = pid; /* Save PID to look for */
return (TRUE);
} else
return (FALSE);
}
/***********************************************************************\
* VOID SpyCheckPIDForSymbol(VOID)
*
* Effect: Only called when we are looking for a symbol
*
\***********************************************************************/
VOID SpyCheckPIDForSymbol()
{
PIDINFO pidinfo;
/*
* Get the spy semaphore to serialize access and see if we are the
* correct PID;
*/
DosGetPID(&pidinfo);
if (DosSemRequest((HSEM)(PULONG)&spyhookSem, 100L) != 0)
return;
if (pidinfo.pid == pidLNSpy) {
/*
* We are the correct process, so continue to try go get the
* symbol information.
*/
pidLNSpy = 0xffff; /* reset to not enter again */
rcLNSpy = IdentifyCodeSelector( selectorLNSpy,
(PWHOISINFO)&whoIsLNSpy);
}
DosSemClear( (HSEM)(PULONG)&spyhookSem );
}
/***********************************************************************\
* int FAR PASCAL SpyGetLNSymbolSelector(pwhoinfo)
*
* Effect: Get the information about the specified selector.
* If the specified process has not been executed since the
* function SpySetLNSymbolPID has been called, it will return -1,
* else it will return what was returned from IdentifyCodeSelector.
\***********************************************************************/
int FAR PASCAL SpyGetLNSymbolSelector(pwhoIsinfo)
PWHOISINFO pwhoIsinfo;
{
*pwhoIsinfo = whoIsLNSpy;
return (rcLNSpy);
}
/**********************************************************************\
* VOID GrabMsgDataWords (SHORT imsg, UCHAR bMPType)
*
* Effect: Gets the next message from the list.
*
* if timeout != 0 on message processing threads, problems may occur.
* if lpqmsg==NULL, this function acts like a query or wait function.
\***********************************************************************/
VOID GrabMsgDataWords(imsg, bMPType)
SHORT imsg;
UCHAR bMPType;
{
UCHAR bMP1Type;
UCHAR bMP2Type;
SHORT cbMPs;
SHORT cbMP1;
SHORT cbMP2;
UCHAR *rgBuf;
/*
* This function will use the MPType data to know if MP1 and/or MP2
* are pointers to any known data, that we want to extract off
* and save for spy to display later
*/
rgqmsgSpy[imsg].bMPType = bMPType;
bMP1Type = bMPType & MP_MASK;
cbMPs = cbMP1 = rgqmsgSpy[imsg].cbDataMP1 = acbMPTypes[bMP1Type];
bMP2Type = (bMPType >> 3) & MP_MASK;
cbMPs += (cbMP2 = rgqmsgSpy[imsg].cbDataMP2 = acbMPTypes[bMP2Type]);
if (cbMPs > 0) {
/* Allocate memory to save the data into */
rgBuf = rgqmsgSpy[imsg].rgData = WinAllocMem(hheapSpyHook, cbMPs);
if (rgBuf != NULL) {
/* Copy the data down, Note: if count is 0 will NOP */
if (cbMP1) {
CopyStruct((CHAR FAR *)rgqmsgSpy[imsg].qmsg.mp1,
rgBuf, cbMP1);
rgBuf += cbMP1;
}
if (cbMP2) {
CopyStruct((CHAR FAR *)rgqmsgSpy[imsg].qmsg.mp2,
rgBuf, cbMP2);
}
}
} else {
rgqmsgSpy[imsg].rgData = NULL;
}
}
/**********************************************************************\
* SpyGetNextMessage (lpqmsg, lpBuf, cbBuf, lTimeOut)
*
* Effect: Get the next message from the list.
* if timeout != 0 on message processing threads, problems may occur.
* if lpqmsg==NULL, this function acts like a query or wait function.
*
* Returns: Whether SpyGetNextMessage succeeds or not.
\***********************************************************************/
BOOL FAR PASCAL SpyGetNextMessage(lpqmsg, lpBuf, cbBuf, lTimeOut)
PQMSGSPY lpqmsg; /* Pointer where the user wants the message stored */
PSZ lpBuf; /* pointer to buffer */
SHORT cbBuf; /* size of buffer in bytes */
LONG lTimeOut; /* Timeout value */
{
SHORT cbMsg; /* Count of bytes associated with message */
/* Quick escape hatch */
if ((lTimeOut == 0) && (cmsgSpy == 0))
return (FALSE); /* Don't Wait */
/*
* Now let's possibly wait for a message
*/
if (cmsgSpy == 0) {
if (DosSemWait((HSEM)(PULONG)&spyMsgSem, lTimeOut) != 0)
return (FALSE); /* No messages after timeout */
if (cmsgSpy == 0)
return (FALSE); /* Still no messages, return condition */
}
/*
* If the lpqmsg is NULL, the user is simply asking if there is
* a message and/or waiting for the message, so don't extract
* the message, but simply return the status.
*/
if (lpqmsg != NULL) {
if (DosSemRequest((HSEM)(PULONG)&spyhookSem, lTimeOut) == 0) {
*lpqmsg = rgqmsgSpy[imsgRead]; /* Extract the message */
cbMsg = rgqmsgSpy[imsgRead].cbDataMP1
+ rgqmsgSpy[imsgRead].cbDataMP2;
if ((cbMsg > 0) && (lpBuf != NULL)) {
if (cbMsg < cbBuf)
cbBuf = cbMsg; /* Number of bytes to copy */
CopyStruct(rgqmsgSpy[imsgRead].rgData, lpBuf, cbBuf);
}
if (cbMsg > 0)
WinFreeMem(hheapSpyHook, rgqmsgSpy[imsgRead].rgData, cbMsg);
/* Also give the caller any additional information on message */
imsgRead++;
if (imsgRead == MAXMSGCNT)
imsgRead = 0; /* Wrap around */
/*
* Decrement count of messages, if we go to zero, set
* the semaphore, so that the next read will suspend until
* the next message
*/
cmsgSpy--;
if (cmsgSpy == 0)
DosSemSet((HSEM)(PULONG)&spyMsgSem);
DosSemClear( (HSEM)(PULONG)&spyhookSem );
}
}
return (TRUE);
}
/***********************************************************************\
* VOID PASCAL Init( hmod )
*
* Effect: Saves the Spy module handle
\***********************************************************************/
VOID PASCAL Init( hmod )
HMODULE hmod;
{
/* Save the module handle */
hmodSpy = hmod;
}
/***********************************************************************\
* UCHAR GMsgEnableAndType (USHORT msg)
*
* Effect:
* Should the message be processed?
*
* If the message is out of range
* or bit is set in message bitmask then return TRUE;
\***********************************************************************/
UCHAR GMsgEnableAndType(msg)
USHORT msg;
{
if (msg > MAXMSGFILTER)
return ((UCHAR)(fDispMsgsNotInList? MP_ENABLED : 0));
return (rgMessageFilter[msg]); /* One byte per message */
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.