--- pmsdk/samples/spy/spyhook.c 2018/08/09 12:28:12 1.1.1.1 +++ pmsdk/samples/spy/spyhook.c 2018/08/09 12:28:20 1.1.1.2 @@ -1,82 +1,123 @@ /***********************************************************************\ -* spyhook.C - Spy Global input hook interface library. -* -* Purpose: This dynlink is needed because global input hooks must -* reside in a DLL. -* -* Created by Microsoft Corp. 1987 +* 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_PM +#define INCL_DOSPROCESS +#define INCL_WINHEAP +#define INCL_WINHOOKS +#define INCL_WINWINDOWMGR #include #include "spyhook.h" - ULONG spyhookSem = 0L; /* global semaphore for this module */ HMODULE hmodSpy; /* dynlink module handle */ -SHORT SpybHooks; /* Which Hooks do we use */ +SHORT SpybHooks; /* Which hook do we use? */ -HAB habOwner = (HAB)0; /* Hook owner's anchor block */ +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 rghwndSpy[MAXHWNDS]; -int chwndSpy = 0; /* Max windows to spy */ +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] = ""; -BOOL FMsgInMsgList(USHORT); /* Is message in message list */ -UCHAR rgBitMasks[8] = {0x01, 0x02, 0x04, 0x08, - 0x10, 0x20, 0x40, 0x80 }; - +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 */ -QMSG rgqmsgSpy[MAXMSGCNT]; /* Array of messages to process */ + +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); - - - -/***************************** Exported Function ***********************\ -* BOOL FAR PASCAL SpyInputHook( hab, lpqmsg ) +/***********************************************************************\ +* 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 chain. +* message to the next guy in the chain. * * Return value: FALSE to pass message to next hook procedure. \***********************************************************************/ -BOOL FAR PASCAL SpyInputHook( hab, lpqmsg ) -HAB hab; -PQMSG lpqmsg; +BOOL FAR PASCAL SpyInputHook( hab, lpqmsg, fs ) +HAB hab; +PQMSG lpqmsg; +USHORT fs; { + UCHAR bMPType; + /* - * First check to see if we are processing any hook messages + * Check first to see if we are looking for a process's symbols */ - if (!fRecording || (cmsgSpy >= MAXMSGCNT)) - return (FALSE); /* No let the next one have it now */ + if (pidLNSpy != 0xffff) + SpyCheckPIDForSymbol(); - if ((chwndSpy == 0) && !fProcessAllWindows && !fProcessAllFrames) - return (FALSE); + /* + * 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. + * 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) && FMsgInMsgList(lpqmsg->msg)) { - rgqmsgSpy[imsgWrite++] = *lpqmsg; /* Save the message */ + 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++; @@ -85,34 +126,42 @@ PQMSG lpqmsg; } DosSemClear( (HSEM)(PULONG)&spyhookSem ); - return FALSE; /* Let system take normal action. */ + return FALSE; /* Let system take normal action */ } -/***************************** Exported Function ***********************\ -* BOOL FAR PASCAL SpySendMsgHook( hab, lpsmh, fInterTask) -* HAB hab; -* PQMSG lpqmsg; +/***********************************************************************\ +* 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 chain. +* 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; +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 || (cmsgSpy >= MAXMSGCNT)) - return (FALSE); /* No let the next one have it now */ + if (!fRecording || !fAnythingToWatch || (cmsgSpy >= MAXMSGCNT)) + return (FALSE); /* No, let the next one have it now */ - if ((chwndSpy == 0) && !fProcessAllWindows && !fProcessAllFrames) - return (FALSE); /* * See if we have any messages to process */ @@ -120,17 +169,28 @@ BOOL fInterTask; return (FALSE); /* Make sure no one got in by mistake */ if (cmsgSpy < MAXMSGCNT) { - if (SpyFWindowInList(lpsmh->hwnd) && FMsgInMsgList(lpsmh->msg)) { - /* - * Store out message, must move pieces seperatly + if (SpyFWindowInList(lpsmh->hwnd, FALSE) && + (bMPType = GMsgEnableAndType(lpsmh->msg))) { + /* + * Store out message, must move pieces separately */ - rgqmsgSpy[imsgWrite].hwnd = lpsmh->hwnd; - rgqmsgSpy[imsgWrite].msg = lpsmh->msg; - rgqmsgSpy[imsgWrite].mp1 = lpsmh->mp1; - rgqmsgSpy[imsgWrite].mp2 = lpsmh->mp2; - rgqmsgSpy[imsgWrite].time = (ULONG)-1; - rgqmsgSpy[imsgWrite].ptl.x = (LONG)fInterTask; - rgqmsgSpy[imsgWrite].ptl.y = 0; + 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) @@ -141,11 +201,11 @@ BOOL fInterTask; } DosSemClear( (HSEM)(PULONG)&spyhookSem ); - return FALSE; /* Let system take normal action. */ + return FALSE; /* Let system take normal action */ } -/*************************** Public Function ***************************\ +/***********************************************************************\ * BOOL FAR PASCAL SpyInstallHook( hab, hmq, fSendMessage, bHooks) * * Effect: This routine installs a system-wide HK_INPUT hook. The hab @@ -161,21 +221,40 @@ HMQ hmq; USHORT bHooks; { BOOL fRet; + SEL selHeap; DosSemRequest( (HSEM)(PULONG)&spyhookSem, -1L); - /* - * Look at hook index if == HK_INPUT Install a system-wide input hook. - * else set system wide SENDMSG hook - */ + /* + * 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 ); + hmodSpy ); if (SpybHooks & SPYH_SENDMSG) fRet = WinSetHook( hab, (HMQ)0, HK_SENDMSG, (PFN)SpySendMsgHook, - hmodSpy ); + hmodSpy ); if (fRet) { habOwner = hab; hmqOwner = hmq; @@ -189,55 +268,75 @@ USHORT bHooks; -/*************************** Public Function ***************************\ +/***********************************************************************\ * 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 +* 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; - for (i=0; i < chwnd; i++) { - rghwndSpy[i] = *rghwnd++; + if (chwndSpy > 0 ) { + + phwndT = pahwndSpy = WinAllocMem(hheapSpyHook, + sizeof(HWND) * chwndSpy); + + if (phwndT != NULL) { + for (i=0; i < chwnd; i++) { + *phwndT++ = *rghwnd++; + } + } else + chwndSpy = 0; } - DosSemClear( (HSEM)(PULONG)&spyhookSem ); + fAnythingToWatch = (chwndSpy > 0) || (chmqSpy > 0) || + fProcessAllWindows || fProcessAllFrames; + DosSemClear( (HSEM)(PULONG)&spyhookSem ); return(TRUE); } -/*************************** Public Function ***************************\ +/***********************************************************************\ * 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 +* 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; + if (chwnd > chwndSpy) + chwnd = chwndSpy; + phwndT = pahwndSpy; for (i=0; i < chwnd; i++) { - *rghwnd++ = rghwndSpy[i]; + *rghwnd++ = *pahwndSpy++; } DosSemClear( (HSEM)(PULONG)&spyhookSem ); @@ -246,16 +345,96 @@ HWND FAR *rghwnd; } -/*************************** Public Function ***************************\ -* BOOL FAR PASCAL SpySetMessageList( chwnd, rghwnd) + + +/***********************************************************************\ +* BOOL FAR PASCAL SpySetQueueList( chmq, rghmq ) * -* Effect: This routine sets the list of window that we are interested -* in watching the messages for. +* 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) * -* Returns value: TRUE +* Effect: This routine sets the list of windows that whose message we watch. +* +* Returns value: TRUE \***********************************************************************/ -BOOL FAR PASCAL SpySetMessageList(prgNewMsgFilter) +BOOL FAR PASCAL SpySetMessageList(prgNewMsgFilter, fNewDispMsgsNotInList) UCHAR FAR *prgNewMsgFilter; +BOOL fNewDispMsgsNotInList; { SHORT i; unsigned char *prgb; @@ -264,6 +443,9 @@ UCHAR FAR *prgNewMsgFilter; prgb = rgMessageFilter; + + fDispMsgsNotInList = fNewDispMsgsNotInList; + for (i=0; i < MAXMSGFILTERBYTES; i++) { *prgb++ = *prgNewMsgFilter++; } @@ -274,27 +456,48 @@ UCHAR FAR *prgNewMsgFilter; } -/*************************** Public Function ***************************\ -* BOOL FAR PASCAL SpyFWindowInList (hwnd) +/***********************************************************************\ +* 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 +* +* 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) +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 */ - for (i=0; i< chwndSpy; i++) { - if (hwnd == rghwndSpy[i]) - return (TRUE); + /* + * 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) { @@ -313,7 +516,7 @@ register HWND hwnd; } -/*************************** Public Function ***************************\ +/***********************************************************************\ * BOOL FAR PASCAL SpyReleaseHook(fZeroQueue) * * Effect: This routine releases the input hook, if it is installed. @@ -328,14 +531,14 @@ BOOL fZeroQueue; 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 ) { + 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; } @@ -347,11 +550,21 @@ BOOL fZeroQueue; * Only do this if the Zeroqueu flag was passed */ if (fZeroQueue) { - cmsgSpy = 0; + cmsgSpy = 0; imsgWrite = 0; - imsgRead = 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); @@ -360,13 +573,13 @@ BOOL fZeroQueue; } -/*************************** Public Function ***************************\ +/***********************************************************************\ * BOOL FAR PASCAL SpyHookOnOrOff( fOn) * * Effect: This routine allows the application to turn the hook * processing on or off. * -* Returns value: +* Returns: TRUE \***********************************************************************/ BOOL FAR PASCAL SpyHookOnOrOff(fOn) BOOL fOn; @@ -381,58 +594,196 @@ BOOL fOn; -/*************************** Public Function ***************************\ +/***********************************************************************\ * BOOL FAR PASCAL SpySetAllFrameOpt(fAllFrames) * * Effect: Special state if TRUE will cause the window filter to pass -* all frame windows through. This is usefull when debuging +* all frame windows through. This is useful when debugging * interactions between frame windows, when the windows are * net yet created. * -* Returns value: +* Returns: TRUE \***********************************************************************/ BOOL FAR PASCAL SpySetAllFrameOpt(fAllFrames) BOOL fAllFrames; { fProcessAllFrames = fAllFrames; + fAnythingToWatch = (chwndSpy > 0) || (chmqSpy > 0) || + fProcessAllWindows || fProcessAllFrames; return (TRUE); } -/*************************** Public Function ***************************\ + +/***********************************************************************\ * BOOL FAR PASCAL 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 +* all windows through. This is useful when debugging +* interactions between all of the windows. * -* Returns value: +* Returns: TRUE \***********************************************************************/ BOOL FAR PASCAL SpySetAllWindowOpt(fAllWindows) BOOL fAllWindows; { fProcessAllWindows = fAllWindows; + fAnythingToWatch = (chwndSpy > 0) || (chmqSpy > 0) || + fProcessAllWindows || fProcessAllFrames; return (TRUE); } -/*************************** Public Function **************************\ -* SpyGetNextMessage (lpqmsg, lTimeOut) + +/***********************************************************************\ +* BOOL FAR PASCAL SpySetLNSymbolPID(PID pid, SELECTOR sel); * -* 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 FAR PASCAL SpyGetNextMessage(lpqmsg, lTimeOut) -PQMSG lpqmsg; -LONG lTimeOut; +* +* 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); /* Dont Wait */ + return (FALSE); /* Don't Wait */ /* - * Now lets possibly wait for a message + * Now let's possibly wait for a message */ if (cmsgSpy == 0) { if (DosSemWait((HSEM)(PULONG)&spyMsgSem, lTimeOut) != 0) @@ -443,12 +794,28 @@ LONG lTimeOut; /* * If the lpqmsg is NULL, the user is simply asking if there is - * a message and/or waiting for the message, so dont extract + * 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 */ + *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 */ @@ -468,44 +835,32 @@ LONG lTimeOut; return (TRUE); } - - - -/*************************** Private Function **************************\ +/***********************************************************************\ * VOID PASCAL Init( hmod ) -* -* Effect: -* -* -* Returns value: +* +* Effect: Saves the Spy module handle \***********************************************************************/ VOID PASCAL Init( hmod ) HMODULE hmod; { - register INT i; - - /* Save the module handle. */ + /* Save the module handle */ hmodSpy = hmod; } - -/*************************** Private Function **************************\ -* Bool FMsgInMsgList (USHORT msg) +/***********************************************************************\ +* 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 +* Should the message be processed? * -* Returns value: -* BOOL +* If the message is out of range +* or bit is set in message bitmask then return TRUE; \***********************************************************************/ -BOOL FMsgInMsgList(msg) +UCHAR GMsgEnableAndType(msg) USHORT msg; { if (msg > MAXMSGFILTER) - return (TRUE); + return ((UCHAR)(fDispMsgsNotInList? MP_ENABLED : 0)); - if (rgMessageFilter[msg >> 3] & rgBitMasks[msg & 0x07]) - return (TRUE); - return (FALSE); + return (rgMessageFilter[msg]); /* One byte per message */ }