|
|
Microsoft OS/2 SDK 2.0 05-30-1990
/***********************************************************************\
* spyhook.C - Spy Global input hook interface library.
*
* Created: Microsoft, IBM Corporation 1990
*
* DISCLAIMER OF WARRANTIES. The following [enclosed] code is
* sample code created by Microsoft Corporation and/or IBM
* Corporation. This sample code is not part of any standard
* Microsoft or IBM product and is provided to you solely for
* the purpose of assisting you in the development of your
* applications. The code is provided "AS IS", without
* warranty of any kind. Neither Microsoft nor IBM shall be
* liable for any damages arising out of your use of the sample
* code, even if they have been advised of the possibility of
* such damages.
*
* Purpose: This dynlink is needed because global input hooks must
* reside in a DLL.
*
\***********************************************************************/
#define INCL_PM
#define INCL_DOSPROCESS
#define INCL_DOSMODULEMGR
#define INCL_DOSSEMAPHORES
#define INCL_ERRORS
#include <os2.h>
#include "spyhk32.h"
// Needed to make a dll link properly
int _acrtused = 0;
HMTX hmtxSpyHook; /* global semaphore for this module */
HEV hevSpyMsg; /* global semaphore for this module */
HMODULE hmodSpy; /* dynlink module handle */
SHORT SpybHooks; /* Whichs Hook do we use */
HAB habOwner = (HAB)0; /* Hook owner's anchore 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 fInitialized = FALSE;
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 */
BOOL CopyStruct(UCHAR *pbSrc, UCHAR *pbDst, SHORT cb); /* Copy bytes */
void DebugBreak(void);
/* Define an array of messages to pass to whomever calls us */
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 */
/* Use the Dos Sub allocate functions to make sure to use shared memory */
#define HEAPSIZE 16384 /* 16K should be plenty? */
PVOID pheapSpyHook; /* Heap to use for Spy Hook DLL */
PBYTE AllocMem(ULONG cb);
VOID FreeMem(PBYTE pMem, ULONG cb);
BOOL EnterSem(ULONG ulWait);
BOOL LeaveSem(VOID);
BOOL SignalEvent(VOID);
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 dont process yet */
sizeof(QMSG) /* MPT_QMSG */
};
/* Information for geting selector information in diffent PID context */
PIT pit = {0xffff, 0, 0L, NULL, 0};
USHORT selectorLNSpy = 0; /* Which Selector */
VOID SpyCheckPIDForIntercept(VOID);
ULONG EXPENTRY Init(ULONG hPDLL, HMODULE hmod);
/***********************************************************************\
* VOID Init( hmod )
*
* Effect: Saves the Spy module handle
\***********************************************************************/
ULONG EXPENTRY Init(hPDLL, hmod)
ULONG hPDLL;
HMODULE hmod;
{
/* Save the module handle */
hmodSpy = hmod;
return (ULONG)hmodSpy;
/* Unreferenced formal parameters referenced here to prevent compiler
warning */
hPDLL;
}
/***************************** Exported Function ***********************\
* BOOL EXPENTRY 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 chain.
*
* Return value: FALSE to pass message to next hook procedure.
\***********************************************************************/
BOOL EXPENTRY SpyInputHook( hab, lpqmsg, fs )
HAB hab;
PQMSG lpqmsg;
USHORT fs;
{
UCHAR bMPType;
/*
* Check first to see if we are looking for a process symbols
*/
if (pit.pid != 0xffff)
SpyCheckPIDForIntercept();
/*
* 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 - Recheck to make sure we
* Dont overwrite our queue.
*/
if (!EnterSem(100L)) {
DebugBreak();
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++;
SignalEvent();
}
}
LeaveSem();
return FALSE; /* Let system take normal action. */
/* Unreferenced formal parameters referenced here to prevent compiler
warning */
hab;
}
/***************************** Exported Function ***********************\
* BOOL EXPENTRY SpySendMsgHook( hab, lpsmh, fInterTask)
* HAB hab;
* PQMSG lpqmsg;
*
* 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 chain.
*
* Return value: FALSE to pass message to next hook procedure.
\***********************************************************************/
BOOL EXPENTRY SpySendMsgHook( hab, lpsmh, fInterTask )
HAB hab;
PSMHSTRUCT lpsmh;
BOOL fInterTask;
{
UCHAR bMPType;
PPIB ppib;
PTIB ptib;
/*
* Check first to see if we are looking for a process symbols
*/
if (pit.pid != 0xffff)
SpyCheckPIDForIntercept();
/*
* 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 (!EnterSem(100L)) {
DebugBreak();
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 seperatly
*/
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 */
DosGetThreadInfo(&ptib, &ppib);
rgqmsgSpy[imsgWrite].pidSend = ppib->pib_ulpid;
rgqmsgSpy[imsgWrite].tidSend = ptib->tib_ultid;
imsgWrite++;
if (imsgWrite == MAXMSGCNT)
imsgWrite = 0; /* Wrap around */
cmsgSpy++;
SignalEvent();
}
}
LeaveSem();
return FALSE; /* Let system take normal action. */
/* Unreferenced formal parameters referenced here to prevent compiler
warning */
hab;
}
/*************************** Public Function ***************************\
* BOOL EXPENTRY 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 EXPENTRY SpyInstallHook( hab, hmq, bHooks )
HAB hab;
HMQ hmq;
USHORT bHooks;
{
BOOL fRet;
ULONG ulPostCt;
EnterSem(-1L);
/*
* Look at hook index if == HK_INPUT 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;
}
DosResetEventSem(hevSpyMsg, &ulPostCt); /* Init, no messages avail */
LeaveSem();
return fRet;
}
/*************************** Public Function ***************************\
* BOOL EXPENTRY SpySetWindowList( chwnd, rghwnd)
*
* Effect: This routine sets the list of window that we are interested
* in watching the messages for.
*
* Returns value: TRUE
\***********************************************************************/
BOOL EXPENTRY SpySetWindowList( chwnd, rghwnd )
SHORT chwnd;
HWND *rghwnd;
{
SHORT i;
HWND *phwndT;
EnterSem(-1L);
if (pahwndSpy) {
FreeMem((char *)pahwndSpy, sizeof(HWND) * chwndSpy);
pahwndSpy = NULL;
}
chwndSpy = chwnd;
if (chwndSpy > 0 ) {
phwndT = pahwndSpy = (HWND *)AllocMem(sizeof(HWND) * chwndSpy);
if (phwndT != NULL) {
for (i=0; i < chwnd; i++) {
*phwndT++ = *rghwnd++;
}
} else
chwndSpy = 0;
}
fAnythingToWatch = (chwndSpy > 0) || (chmqSpy > 0) ||
fProcessAllWindows || fProcessAllFrames;
LeaveSem();
return(TRUE);
}
/*************************** Public Function ***************************\
* BOOL EXPENTRY SpyGetWindowList( chwnd, rghwnd)
*
* Effect: This routine sets the list of window that we are interested
* in watching the messages for.
*
* Returns value: TRUE
\***********************************************************************/
SHORT EXPENTRY SpyGetWindowList( chwnd, rghwnd )
SHORT chwnd;
HWND *rghwnd;
{
SHORT i;
HWND *phwndT;
EnterSem(-1L);
if (chwnd > chwndSpy)
chwnd = chwndSpy;
phwndT = pahwndSpy;
for (i=0; i < chwnd; i++) {
*rghwnd++ = *phwndT++;
}
LeaveSem();
return(chwnd);
}
/*************************** Public Function ***************************\
* BOOL EXPENTRY SpySetQueueList( chmq, rghmq)
*
* Effect: This routine sets the list of Queue that we are interested
* in watching the messages for.
*
* Returns value: TRUE
\***********************************************************************/
BOOL EXPENTRY SpySetQueueList( chmq, rghmq )
SHORT chmq;
HMQ *rghmq;
{
SHORT i;
HMQ *phmqT;
EnterSem(-1L);
/*
* If we previously had a list of HMQs to spy on, free the old list
* now
*/
if (pahmqSpy != NULL) {
FreeMem((char *)pahmqSpy, sizeof(HMQ) * chmqSpy);
pahmqSpy = NULL;
}
chmqSpy = chmq;
if (chmqSpy > 0) {
phmqT = pahmqSpy = (HMQ *)AllocMem(sizeof(HMQ) * chmqSpy);
if (phmqT != NULL) {
for (i=0; i < chmq; i++) {
*phmqT++ = *rghmq++;
}
} else
chmqSpy = 0;
}
fAnythingToWatch = (chwndSpy > 0) || (chmqSpy > 0) ||
fProcessAllWindows || fProcessAllFrames;
LeaveSem();
return(TRUE);
}
/*************************** Public Function ***************************\
* BOOL EXPENTRY SpyGetQueueList( chmq, rghmq)
*
* Effect: This routine sets the list of Queue that we are interested
* in watching the messages for.
*
* Returns value: TRUE
\***********************************************************************/
SHORT EXPENTRY SpyGetQueueList( chmq, rghmq )
SHORT chmq;
HMQ *rghmq;
{
SHORT i;
HMQ *phmqT;
EnterSem(-1L);
if (chmq > chmqSpy)
chmq = chmqSpy;
phmqT = pahmqSpy;
for (i=0; i < chmq; i++) {
*rghmq++ = *phmqT++;
}
LeaveSem();
return(chmq);
}
/*************************** Public Function ***************************\
* BOOL EXPENTRY SpySetMessageList(UCHAR *prgNewMsgFilter,
* BOOL fNewDispMsgsNotInList)
*
* Effect: This routine sets the list of window that we are interested
* in watching the messages for.
*
* Returns value: TRUE
\***********************************************************************/
BOOL EXPENTRY SpySetMessageList(prgNewMsgFilter, fNewDispMsgsNotInList)
UCHAR *prgNewMsgFilter;
BOOL fNewDispMsgsNotInList;
{
SHORT i;
unsigned char *prgb;
EnterSem(-1L);
prgb = rgMessageFilter;
fDispMsgsNotInList = fNewDispMsgsNotInList;
for (i=0; i < MAXMSGFILTERBYTES; i++) {
*prgb++ = *prgNewMsgFilter++;
}
LeaveSem();
return(TRUE);
}
/*************************** Public Function ***************************\
* BOOL EXPENTRY 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 EXPENTRY 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 */
PPIB ppib;
PTIB ptib;
MQINFO mqinfo; /* Queue info */
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) {
if (hwnd != NULL) {
/*
* Sent to specific window First see if the user has specified
* that the want all messages that are sent to this message
* queue
*/
hmqWindow = (HMQ)WinQueryWindowULong(hwnd, QWL_HMQ);
for (i=0; i < chmqSpy; i++) {
if (*phmqT++ == hmqWindow)
return (TRUE);
}
} else {
// For NULL window handle, see if the current process has HMQ
/*
* Null Window handle, so instead we need to go through the
* list of queues we are watching and see if their PID and TID
* matches our current thread.
*/
DosGetThreadInfo(&ptib, &ppib);
for (i=0; i < chmqSpy; i++) {
if (WinQueryQueueInfo(*phmqT, &mqinfo, sizeof(mqinfo))) {
if ((mqinfo.pid == ppib->pib_ulpid) &&
(mqinfo.tid == ptib->tib_ultid))
return (TRUE); // Yes we want this queue!
}
phmqT++;
}
}
}
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);
}
/*************************** Public Function ***************************\
* BOOL EXPENTRY SpyReleaseHook(fZeroQueue)
*
* Effect: This routine releases the input hook, if it is installed.
*
* Returns value: TRUE if hook is released, FALSE otherwise.
\***********************************************************************/
BOOL EXPENTRY SpyReleaseHook(fZeroQueue)
BOOL fZeroQueue;
{
BOOL fRet;
EnterSem(-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)
FreeMem((char *)pahwndSpy, sizeof(HWND) * chwndSpy);
pahwndSpy = NULL;
chwndSpy = 0; /* Max windows to spy */
fRecording = FALSE; /* Set recording to off */
if (pahmqSpy != NULL)
FreeMem((char *)pahmqSpy, sizeof(HMQ) * chmqSpy);
pahmqSpy = NULL;
chmqSpy = 0;
fAnythingToWatch = FALSE;
SignalEvent(); /* Free any process */
}
LeaveSem();
return fRet;
}
/*************************** Public Function ***************************\
* BOOL EXPENTRY SpyHookOnOrOff( fOn)
*
* Effect: This routine allows the application to turn the hook
* processing on or off.
*
* Returns value:
\***********************************************************************/
BOOL EXPENTRY SpyHookOnOrOff(fOn)
BOOL fOn;
{
EnterSem(-1L);
fRecording = fOn;
LeaveSem();
return (TRUE);
}
/*************************** Public Function ***************************\
* BOOL EXPENTRY SpySetAllFrameOpt(fAllFrames)
*
* Effect: Special state if TRUE will cause the window filter to pass
* all frame windows through. This is usefull when debuging
* interactions between frame windows, when the windows are
* net yet created.
*
* Returns value:
\***********************************************************************/
BOOL EXPENTRY SpySetAllFrameOpt(fAllFrames)
BOOL fAllFrames;
{
fProcessAllFrames = fAllFrames;
fAnythingToWatch = (chwndSpy > 0) || (chmqSpy > 0) ||
fProcessAllWindows || fProcessAllFrames;
return (TRUE);
}
/*************************** Public Function ***************************\
* BOOL EXPENTRY SpySetAllWindowOpt(fAllWindows)
*
* Effect: Special state if TRUE will cause the window filter to pass
* all windows through. This is usefull when debuging
* interactions between all of the windows
*
* Returns value:
\***********************************************************************/
BOOL EXPENTRY SpySetAllWindowOpt(fAllWindows)
BOOL fAllWindows;
{
fProcessAllWindows = fAllWindows;
fAnythingToWatch = (chwndSpy > 0) || (chmqSpy > 0) ||
fProcessAllWindows || fProcessAllFrames;
return (TRUE);
}
/*************************** Public Function ***************************\
* BOOL EXPENTRY SpySetPIDIntercept(PID pid, USHORT usPIT, ULONG ulInfo);
*
*
* Effect: Hack to tell the hook to be on the look out for a specific
* PID. If it finds it is running in the context of the specified
* process, it will get the selector information for the specified
* selector.
*
* Returns value:
\***********************************************************************/
BOOL EXPENTRY SpySetPIDIntercept(pid, usPIT, ulInfo)
PID pid;
USHORT usPIT;
ULONG ulInfo;
{
if (pit.pid == 0xffff) {
pit.pid = pid;
pit.usPIT = usPIT;
pit.ulInfo = ulInfo;
return (TRUE);
} else
return (FALSE);
}
/***************************** Exported Function ***********************\
* VOID SpyCheckPIDForIntercept(VOID)
*
* Effect: Only called when we are looking for a symbol
*
\***********************************************************************/
VOID SpyCheckPIDForIntercept()
{
PPIB ppib;
PTIB ptib;
/*
* Get the spy semaphore to serialize access and see if we are the
* correct PID;
*/
DosGetThreadInfo(&ptib, &ppib);
if (!EnterSem(100L))
return;
if (ppib->pib_ulpid == pit.pid) {
/*
* We are the correct process, so continue to try go get the
* symbol information.
*/
pit.pid = 0xffff; /* reset to not enter again */
switch (pit.usPIT) {
break;
case PIT_ACCEL:
// Allocate memory for the Accel table.
pit.cbData = WinCopyAccelTable((HACCEL)pit.ulInfo,
(PACCELTABLE)NULL, 0);
pit.pvoidData = AllocMem(pit.cbData);
if (pit.pvoidData == NULL) {
pit.cbData = 0;
break;
}
WinCopyAccelTable((HACCEL)pit.ulInfo,
(PACCELTABLE)pit.pvoidData, pit.cbData);
break;
}
}
LeaveSem();
}
/*************************** Public Function ***************************\
* int EXPENTRY SpyGetLNSymbolSelector(pwhoinfo)
*
* Effect: Hack to get the information about the specified selector.
* If the specified process has not been executed since the
* function SpySetPIDIntercept has been called, it will return -1,
* else it will return what was returned from IdentifyCodeSelector.
*
* Returns value:
\***********************************************************************/
USHORT EXPENTRY SpyGetPIDInterceptData(pvoidBuffer, cbBuffer, pmresult)
PVOID pvoidBuffer;
USHORT cbBuffer;
PMRESULT pmresult;
{
if (pvoidBuffer != NULL) {
if (pit.pvoidData != NULL) {
if (cbBuffer > pit.cbData)
cbBuffer = pit.cbData;
CopyStruct(pit.pvoidData, pvoidBuffer, cbBuffer);
FreeMem(pit.pvoidData, pit.cbData);
pit.pvoidData = NULL;
}
}
if (pmresult != NULL)
*pmresult = pit.mresult;
return (pit.cbData);
}
/*************************** Public Function **************************\
* VOID GrabMsgDataWords (SHORT imsg, UCHAR bMPType)
*
* Effect:
* Get the next message from the list - if timeout != 0 an message
* processing threads, you may have problems, - If lpqmsg==NULL, this
* function acts like a query or wait function.
*
* Returns value:
\***********************************************************************/
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 = AllocMem(cbMPs);
if (rgBuf != NULL) {
/* Copy the data down, Note: if count is 0 will NOP */
if (cbMP1) {
rgqmsgSpy[imsg].fMP1Valid = CopyStruct(
(CHAR *)rgqmsgSpy[imsg].qmsg.mp1, rgBuf, cbMP1);
rgBuf += cbMP1;
}
if (cbMP2) {
rgqmsgSpy[imsg].fMP2Valid = CopyStruct(
(CHAR *)rgqmsgSpy[imsg].qmsg.mp2, rgBuf, cbMP2);
}
}
} else {
rgqmsgSpy[imsg].rgData = NULL;
}
}
/*************************** Public Function **************************\
* SpyGetNextMessage (lpqmsg, lpBuf, cbBuf, lTimeOut)
*
* Effect:
* Get the next message from the list - if timeout != 0 an message
* processing threads, you may have problems, - If lpqmsg==NULL, this
* function acts like a query or wait function.
*
* Returns value:
\***********************************************************************/
BOOL EXPENTRY 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 */
ULONG ulPostCt; /* Count of posts to semaphore before reset */
/* Quick escape hatch */
if ((lTimeOut == 0) && (cmsgSpy == 0))
return (FALSE); /* Dont Wait */
/*
* Now lets possibly wait for a message
*/
if (cmsgSpy == 0) {
if (DosWaitEventSem(hevSpyMsg, 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 dont extract
* the message, but simply return the status.
*/
if (lpqmsg != NULL) {
if (DosRequestMutexSem(hmtxSpyHook, 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)
FreeMem(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)
DosResetEventSem(hevSpyMsg, &ulPostCt);
LeaveSem();
}
}
return (TRUE);
}
/*************************** Private Function **************************\
* VOID SpyInitializeHookt(void)
*
* Effect:
*
*
* Returns value:
\***********************************************************************/
BOOL EXPENTRY SpyInitializeHook (VOID)
{
if (fInitialized) {
return (TRUE);
}
fInitialized = TRUE;
/* Make an event semaphore to signal spy program with */
DosCreateMutexSem(NULL, &hmtxSpyHook, DC_SEM_SHARED, FALSE);
DosCreateEventSem(NULL, &hevSpyMsg, DC_SEM_SHARED, FALSE);
/* Initialize our local heap */
DosAllocSharedMem(&pheapSpyHook, NULL, HEAPSIZE,
PAG_COMMIT | PAG_READ | PAG_WRITE | OBJ_GETTABLE);
DosSubSet((PVOID)pheapSpyHook, 1, HEAPSIZE);
/* Get the module handle. */
return TRUE;
}
/*************************** Private Function **************************\
* VOID SpyTerminateHook( )
*
* Effect:
*
*
* Returns value:
\***********************************************************************/
BOOL EXPENTRY SpyTerminateHook (VOID)
{
if (!fInitialized) {
return (FALSE);
}
fInitialized = FALSE;
/* Close the semaphore off now */
DosCloseMutexSem(hmtxSpyHook);
DosCloseEventSem(hevSpyMsg);
/* Also need to free memory */
}
/*************************** Private Function **************************\
* UCHAR GMsgEnableAndType (USHORT msg)
*
* Effect:
* Should the message be processed. If the message is out of range,
* or bit is set in message bitmask return TRUE
*
* Returns value:
* BOOL
\***********************************************************************/
UCHAR GMsgEnableAndType(msg)
USHORT msg;
{
if (msg > MAXMSGFILTER)
return ((UCHAR)(fDispMsgsNotInList? MP_ENABLED : 0));
return (rgMessageFilter[msg]); /* One byte per message */
}
/*************************** Private Function **************************\
* PBYTE AllocMem (ULONG cb)
*
* Effect:
* Allocates memory from our local heap, and hides that we are no longer
* calling WinAllocMem.
*
* Returns value:
* PBYTE
\***********************************************************************/
PBYTE AllocMem(ULONG cb)
{
PVOID pbT;
ULONG ulCb;
ULONG ulFlag;
if (DosQueryMem(pheapSpyHook, &ulCb, &ulFlag)) {
if (DosGetSharedMem(pheapSpyHook, PAG_READ | PAG_WRITE)) {
DebugBreak;
return (NULL);
}
}
if (DosSubAlloc((PVOID)pheapSpyHook, (PPVOID)&pbT, cb))
return(NULL);
return(pbT);
}
/*************************** Private Function **************************\
* UCHAR FreeMem (PBYTE pMem, ULONG cb)
*
* Effect:
* Frees any memory previously allocated by Allocmem
*
* Returns value:
* NULL
\***********************************************************************/
VOID FreeMem(PBYTE pMem, ULONG cb)
{
DosSubFree((PVOID)pheapSpyHook, (PVOID)pMem, cb);
}
/*************************** Private Function **************************\
* BOOL EnterSem
*
* Effect:
* Enters the Main spy Mutex semaphore
*
* Returns value:
* BOOL;
\***********************************************************************/
BOOL EnterSem(ULONG ulWait)
{
ULONG rc;
HMTX hmtx;
if ((rc = DosRequestMutexSem(hmtxSpyHook, ulWait)) == 0)
return (TRUE);
if (rc != ERROR_INVALID_HANDLE)
return (FALSE);
#ifdef LATER
* We should Close semaphore when we are done???
#endif
hmtx = hmtxSpyHook;
if (DosOpenMutexSem(NULL, &hmtx) != 0)
return (FALSE);
DosGetSharedMem(pheapSpyHook, PAG_READ | PAG_WRITE);
return (DosRequestMutexSem(hmtxSpyHook, 100L) == 0);
}
/*************************** Private Function **************************\
* BOOL LeaveSem
*
* Effect:
* Enters the Main spy Mutex semaphore
*
* Returns value:
* BOOL;
\***********************************************************************/
BOOL LeaveSem()
{
return (DosReleaseMutexSem(hmtxSpyHook) == 0);
}
/*************************** Private Function **************************\
* BOOL SignalEvent
*
* Effect:
* Signal an event to spy to let him know something is available.
*
* Returns value:
* BOOL;
\***********************************************************************/
BOOL SignalEvent()
{
ULONG rc;
HEV hev;
if ((rc = DosPostEventSem(hevSpyMsg)) == 0)
return (TRUE);
if (rc != ERROR_INVALID_HANDLE)
return (FALSE);
#ifdef LATER
* We should Close semaphore when we are done???
#endif
hev = hevSpyMsg;
if (DosOpenEventSem(NULL, &hev) != 0)
return (FALSE);
return (DosPostEventSem(hevSpyMsg) == 0);
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.