|
|
1.1 root 1: /***********************************************************************\ 1.1.1.2 ! root 2: * spyhook.c - Spy global input hook interface library ! 3: * Created by Microsoft Corporation, 1989 1.1 root 4: * 1.1.1.2 ! root 5: * This dynlink is needed because global input hooks must reside in a DLL. 1.1 root 6: \***********************************************************************/ 1.1.1.2 ! root 7: #define INCL_DOSPROCESS ! 8: #define INCL_WINHEAP ! 9: #define INCL_WINHOOKS ! 10: #define INCL_WINWINDOWMGR 1.1 root 11: #include <os2.h> 12: #include "spyhook.h" 13: 14: ULONG spyhookSem = 0L; /* global semaphore for this module */ 15: HMODULE hmodSpy; /* dynlink module handle */ 1.1.1.2 ! root 16: SHORT SpybHooks; /* Which hook do we use? */ 1.1 root 17: 1.1.1.2 ! root 18: HAB habOwner = (HAB)0; /* Hook owner's anchor block */ 1.1 root 19: HMQ hmqOwner = (HMQ)0; /* Hook owner's message queue */ 20: BOOL fRecording = FALSE; /* Are we recording now? */ 1.1.1.2 ! root 21: BOOL fAnythingToWatch = FALSE; /* Is there anything to watch? */ ! 22: BOOL fDispMsgsNotInList = TRUE; /* Disp msgs not in list? */ 1.1 root 23: 24: /* Define array of window handles that we are going to process */ 1.1.1.2 ! root 25: BOOL fProcessAllFrames = FALSE; /* Are we processing all frame messages?*/ ! 26: BOOL fProcessAllWindows = FALSE;/* Are we processing all windows?*/ ! 27: HWND *pahwndSpy = NULL; /* Array of hwnds to spy on, no max here */ ! 28: int chwndSpy = 0; /* Max windows to spy */ ! 29: ! 30: /* Define array of HMQ's to spy on */ ! 31: HMQ *pahmqSpy = NULL; /* HMQ list to spy on */ ! 32: int chmqSpy = 0; /* Count of hmqs we are spying on */ ! 33: 1.1 root 34: 35: /* Define message filter array */ 36: UCHAR rgMessageFilter[MAXMSGFILTERBYTES] = ""; 1.1.1.2 ! root 37: UCHAR GMsgEnableAndType(USHORT); /* Is message in message list?*/ ! 38: VOID GrabMsgDataWords(SHORT, UCHAR); /* Get extra words for message */ ! 39: VOID CopyStruct(UCHAR FAR *pbSrc, UCHAR FAR *pbDst, SHORT cb);/* Copy bytes */ 1.1 root 40: 41: /* Define an array of messages to pass to whomever calls us */ 42: ULONG spyMsgSem = 0L; /* global semaphore for this module */ 1.1.1.2 ! root 43: ! 44: QMSGSPY rgqmsgSpy[MAXMSGCNT]; /* Array of messages to process */ 1.1 root 45: SHORT cmsgSpy = 0; /* Count of messages yet to be read */ 46: SHORT imsgWrite = 0; /* Index to message to write out */ 47: SHORT imsgRead = 0; /* Index to message to read */ 48: 1.1.1.2 ! root 49: HHEAP hheapSpyHook; /* Heap for SpyHook DLL */ ! 50: SHORT acbMPTypes[MP_MASK+1] = { /* Number of desired bytes to extract */ ! 51: 0, /* Normal fields, no pointers */ ! 52: sizeof(SWP), /* MPT_SWP */ ! 53: sizeof(RECTL), /* MPT_RECTL */ ! 54: 0, /* MPT_WNDPRMS we don't process yet */ ! 55: sizeof(QMSG) /* MPT_QMSG */ ! 56: }; ! 57: ! 58: ! 59: /* Information for getting selector information in different PID context */ ! 60: PID pidLNSpy = 0xffff; /* Which process */ ! 61: USHORT selectorLNSpy = 0; /* Which Selector */ ! 62: WHOISINFO whoIsLNSpy; /* Symbol information */ ! 63: int rcLNSpy = -1; /* Return code */ ! 64: ! 65: ! 66: /* Define all external functions */ ! 67: extern VOID BuildStackTrace(CHAR FAR *, SHORT, SHORT); ! 68: ! 69: /* Define all function prototypes */ ! 70: VOID SpyCheckPIDForSymbol(VOID); ! 71: BOOL FAR PASCAL SpyInputHook(HAB, PQMSG, USHORT); ! 72: BOOL FAR PASCAL SpySendMsgHook(HAB, PSMHSTRUCT, USHORT); ! 73: VOID PASCAL Init(HMODULE); 1.1 root 74: 1.1.1.2 ! root 75: /***********************************************************************\ ! 76: * BOOL FAR PASCAL SpyInputHook( hab, lpqmsg, fs ) 1.1 root 77: * HAB hab; 78: * PQMSG lpqmsg; 1.1.1.2 ! root 79: * USHORT fs; 1.1 root 80: * 81: * Effect: This is the global input hook procedure. Note that hook 82: * procedures can be chained, so we always return FALSE to pass the 1.1.1.2 ! root 83: * message to the next guy in the chain. 1.1 root 84: * 85: * Return value: FALSE to pass message to next hook procedure. 86: \***********************************************************************/ 1.1.1.2 ! root 87: BOOL FAR PASCAL SpyInputHook( hab, lpqmsg, fs ) ! 88: HAB hab; ! 89: PQMSG lpqmsg; ! 90: USHORT fs; 1.1 root 91: { 1.1.1.2 ! root 92: UCHAR bMPType; ! 93: 1.1 root 94: /* 1.1.1.2 ! root 95: * Check first to see if we are looking for a process's symbols 1.1 root 96: */ 1.1.1.2 ! root 97: if (pidLNSpy != 0xffff) ! 98: SpyCheckPIDForSymbol(); 1.1 root 99: 1.1.1.2 ! root 100: /* ! 101: * First check to see if we are processing any hook messages ! 102: */ ! 103: if (!fRecording || !fAnythingToWatch || (cmsgSpy >= MAXMSGCNT)) ! 104: return (FALSE); /* No, let the next one have it now */ 1.1 root 105: 106: /* 1.1.1.2 ! root 107: * See if we have any messages to process - re-check to make sure we ! 108: * don't overwrite our queue. 1.1 root 109: */ 110: if (DosSemRequest((HSEM)(PULONG)&spyhookSem, 100L) != 0) 111: return (FALSE); 112: if (cmsgSpy < MAXMSGCNT) { 1.1.1.2 ! root 113: if (SpyFWindowInList(lpqmsg->hwnd, FALSE) && ! 114: (bMPType = GMsgEnableAndType(lpqmsg->msg))) { ! 115: rgqmsgSpy[imsgWrite].fs = fs; /* Save the flags */ ! 116: rgqmsgSpy[imsgWrite].qmsg = *lpqmsg; /* Save the message */ ! 117: ! 118: GrabMsgDataWords(imsgWrite, bMPType); ! 119: imsgWrite++; ! 120: 1.1 root 121: if (imsgWrite == MAXMSGCNT) 122: imsgWrite = 0; /* Wrap around */ 123: cmsgSpy++; 124: DosSemClear((HSEM)(PULONG)&spyMsgSem); 125: } 126: } 127: 128: DosSemClear( (HSEM)(PULONG)&spyhookSem ); 1.1.1.2 ! root 129: return FALSE; /* Let system take normal action */ 1.1 root 130: } 131: 132: 1.1.1.2 ! root 133: /***********************************************************************\ ! 134: * BOOL FAR PASCAL SpySendMsgHook( hab, lpsmh, fInterTask ) ! 135: * HAB hab; ! 136: * PSMHSTRUCT lpsmh; ! 137: * BOOL fInterTask; 1.1 root 138: * 139: * Effect: This is the global input hook procedure. Note that hook 140: * procedures can be chained, so we always return FALSE to pass the 1.1.1.2 ! root 141: * message to the next guy in the chain. 1.1 root 142: * 143: * Return value: FALSE to pass message to next hook procedure. 144: \***********************************************************************/ 145: BOOL FAR PASCAL SpySendMsgHook( hab, lpsmh, fInterTask ) 1.1.1.2 ! root 146: HAB hab; 1.1 root 147: PSMHSTRUCT lpsmh; 148: BOOL fInterTask; 149: { 1.1.1.2 ! root 150: UCHAR bMPType; ! 151: PIDINFO pidinfo; ! 152: ! 153: /* ! 154: * Check first to see if we are looking for a process's symbols ! 155: */ ! 156: if (pidLNSpy != 0xffff) ! 157: SpyCheckPIDForSymbol(); ! 158: 1.1 root 159: /* 160: * First check to see if we are processing any hook messages 161: */ 1.1.1.2 ! root 162: if (!fRecording || !fAnythingToWatch || (cmsgSpy >= MAXMSGCNT)) ! 163: return (FALSE); /* No, let the next one have it now */ 1.1 root 164: 165: /* 166: * See if we have any messages to process 167: */ 168: if (DosSemRequest((HSEM)(PULONG)&spyhookSem, 100L) != 0) 169: return (FALSE); 170: /* Make sure no one got in by mistake */ 171: if (cmsgSpy < MAXMSGCNT) { 1.1.1.2 ! root 172: if (SpyFWindowInList(lpsmh->hwnd, FALSE) && ! 173: (bMPType = GMsgEnableAndType(lpsmh->msg))) { ! 174: /* ! 175: * Store out message, must move pieces separately 1.1 root 176: */ 1.1.1.2 ! root 177: rgqmsgSpy[imsgWrite].fs = fInterTask; ! 178: rgqmsgSpy[imsgWrite].qmsg.hwnd = lpsmh->hwnd; ! 179: rgqmsgSpy[imsgWrite].qmsg.msg = lpsmh->msg; ! 180: rgqmsgSpy[imsgWrite].qmsg.mp1 = lpsmh->mp1; ! 181: rgqmsgSpy[imsgWrite].qmsg.mp2 = lpsmh->mp2; ! 182: rgqmsgSpy[imsgWrite].qmsg.time = (ULONG)-1; ! 183: rgqmsgSpy[imsgWrite].qmsg.ptl.x = 0; ! 184: rgqmsgSpy[imsgWrite].qmsg.ptl.y = 0; ! 185: ! 186: GrabMsgDataWords(imsgWrite, bMPType); ! 187: ! 188: /* Now get the PID/TID info, and do the stack backtrace */ ! 189: DosGetPID(&pidinfo); ! 190: rgqmsgSpy[imsgWrite].pidSend = pidinfo.pid; ! 191: rgqmsgSpy[imsgWrite].tidSend = pidinfo.tid; ! 192: BuildStackTrace((CHAR FAR *)rgqmsgSpy[imsgWrite].pvoidStack, ! 193: CALLSTOSKIP, MAXSTRACE); 1.1 root 194: 195: imsgWrite++; 196: if (imsgWrite == MAXMSGCNT) 197: imsgWrite = 0; /* Wrap around */ 198: cmsgSpy++; 199: DosSemClear((HSEM)(PULONG)&spyMsgSem); 200: } 201: } 202: 203: DosSemClear( (HSEM)(PULONG)&spyhookSem ); 1.1.1.2 ! root 204: return FALSE; /* Let system take normal action */ 1.1 root 205: } 206: 207: 1.1.1.2 ! root 208: /***********************************************************************\ 1.1 root 209: * BOOL FAR PASCAL SpyInstallHook( hab, hmq, fSendMessage, bHooks) 210: * 211: * Effect: This routine installs a system-wide HK_INPUT hook. The hab 212: * hmq are remembered for message posting. Note that we only allow 213: * one input hook to be installed through this routine, but other 214: * apps may call WinSetHook directly. 215: * 216: * Returns value: TRUE if hook installed successfully, FALSE otherwise. 217: \***********************************************************************/ 218: BOOL FAR PASCAL SpyInstallHook( hab, hmq, bHooks ) 219: HAB hab; 220: HMQ hmq; 221: USHORT bHooks; 222: { 223: BOOL fRet; 1.1.1.2 ! root 224: SEL selHeap; 1.1 root 225: 226: DosSemRequest( (HSEM)(PULONG)&spyhookSem, -1L); 227: 1.1.1.2 ! root 228: /* ! 229: * If this is the first time through, we need to create a local heap ! 230: * to store message information. ! 231: */ ! 232: if (hheapSpyHook == NULL) { ! 233: selHeap = (SEL)(((ULONG)((PSZ)&hheapSpyHook)) >> 16); ! 234: hheapSpyHook = WinCreateHeap(selHeap, 1024, 0, 0, 100, ! 235: HM_MOVEABLE | HM_VALIDSIZE); ! 236: if (hheapSpyHook == NULL) ! 237: return (FALSE); ! 238: } ! 239: ! 240: ! 241: ! 242: /* ! 243: * Look at hook index. ! 244: * ! 245: * if it equals HK_INPUT then ! 246: * install a system-wide input hook ! 247: * else ! 248: * set system wide SENDMSG hook ! 249: */ 1.1 root 250: SpybHooks = bHooks; 251: if (SpybHooks & SPYH_INPUT) 252: fRet = WinSetHook( hab, (HMQ)0, HK_INPUT, (PFN)SpyInputHook, 1.1.1.2 ! root 253: hmodSpy ); 1.1 root 254: 255: if (SpybHooks & SPYH_SENDMSG) 256: fRet = WinSetHook( hab, (HMQ)0, HK_SENDMSG, (PFN)SpySendMsgHook, 1.1.1.2 ! root 257: hmodSpy ); 1.1 root 258: if (fRet) { 259: habOwner = hab; 260: hmqOwner = hmq; 261: } 262: 263: DosSemSet((HSEM)(PULONG)&spyMsgSem); /* Init, no messages avail */ 264: DosSemClear( (HSEM)(PULONG)&spyhookSem ); 265: 266: return fRet; 267: } 268: 269: 270: 1.1.1.2 ! root 271: /***********************************************************************\ 1.1 root 272: * BOOL FAR PASCAL SpySetWindowList( chwnd, rghwnd) 273: * 274: * Effect: This routine sets the list of window that we are interested 275: * in watching the messages for. 276: * 1.1.1.2 ! root 277: * Returns value: TRUE 1.1 root 278: \***********************************************************************/ 279: BOOL FAR PASCAL SpySetWindowList( chwnd, rghwnd ) 280: SHORT chwnd; 281: HWND FAR *rghwnd; 282: { 283: SHORT i; 1.1.1.2 ! root 284: HWND *phwndT; 1.1 root 285: 286: DosSemRequest( (HSEM)(PULONG)&spyhookSem, -1L); 287: 1.1.1.2 ! root 288: if (pahwndSpy) { ! 289: WinFreeMem(hheapSpyHook, (char *)pahwndSpy, sizeof(HWND) * chwndSpy); ! 290: pahwndSpy = NULL; ! 291: } ! 292: ! 293: 1.1 root 294: chwndSpy = chwnd; 295: 1.1.1.2 ! root 296: if (chwndSpy > 0 ) { ! 297: ! 298: phwndT = pahwndSpy = WinAllocMem(hheapSpyHook, ! 299: sizeof(HWND) * chwndSpy); ! 300: ! 301: if (phwndT != NULL) { ! 302: for (i=0; i < chwnd; i++) { ! 303: *phwndT++ = *rghwnd++; ! 304: } ! 305: } else ! 306: chwndSpy = 0; 1.1 root 307: } 308: 1.1.1.2 ! root 309: fAnythingToWatch = (chwndSpy > 0) || (chmqSpy > 0) || ! 310: fProcessAllWindows || fProcessAllFrames; 1.1 root 311: 1.1.1.2 ! root 312: DosSemClear( (HSEM)(PULONG)&spyhookSem ); 1.1 root 313: return(TRUE); 314: } 315: 316: 1.1.1.2 ! root 317: /***********************************************************************\ 1.1 root 318: * BOOL FAR PASCAL SpyGetWindowList( chwnd, rghwnd) 319: * 320: * Effect: This routine sets the list of window that we are interested 321: * in watching the messages for. 322: * 1.1.1.2 ! root 323: * Returns value: TRUE 1.1 root 324: \***********************************************************************/ 325: SHORT FAR PASCAL SpyGetWindowList( chwnd, rghwnd ) 326: SHORT chwnd; 327: HWND FAR *rghwnd; 328: { 329: SHORT i; 1.1.1.2 ! root 330: HWND *phwndT; 1.1 root 331: 332: DosSemRequest( (HSEM)(PULONG)&spyhookSem, -1L); 333: 1.1.1.2 ! root 334: if (chwnd > chwndSpy) ! 335: chwnd = chwndSpy; 1.1 root 336: 1.1.1.2 ! root 337: phwndT = pahwndSpy; 1.1 root 338: for (i=0; i < chwnd; i++) { 1.1.1.2 ! root 339: *rghwnd++ = *pahwndSpy++; 1.1 root 340: } 341: 342: DosSemClear( (HSEM)(PULONG)&spyhookSem ); 343: 344: return(chwnd); 345: } 346: 347: 1.1.1.2 ! root 348: ! 349: ! 350: /***********************************************************************\ ! 351: * BOOL FAR PASCAL SpySetQueueList( chmq, rghmq ) 1.1 root 352: * 1.1.1.2 ! root 353: * Effect: This routine sets the list of queues whose messages we watch. ! 354: * ! 355: * Returns value: TRUE ! 356: \***********************************************************************/ ! 357: BOOL FAR PASCAL SpySetQueueList( chmq, rghmq ) ! 358: SHORT chmq; ! 359: HMQ FAR *rghmq; ! 360: { ! 361: SHORT i; ! 362: HMQ *phmqT; ! 363: ! 364: DosSemRequest( (HSEM)(PULONG)&spyhookSem, -1L); ! 365: ! 366: /* ! 367: * If we previously had a list of HMQs to spy on, free the old list ! 368: * now ! 369: */ ! 370: if (pahmqSpy != NULL) { ! 371: WinFreeMem(hheapSpyHook, (char *)pahmqSpy, sizeof(HMQ) * chmqSpy); ! 372: pahmqSpy = NULL; ! 373: } ! 374: ! 375: chmqSpy = chmq; ! 376: ! 377: if (chmqSpy > 0) { ! 378: phmqT = pahmqSpy = WinAllocMem(hheapSpyHook, sizeof(HMQ) * chmqSpy); ! 379: ! 380: if (phmqT != NULL) { ! 381: for (i=0; i < chmq; i++) { ! 382: *phmqT++ = *rghmq++; ! 383: } ! 384: } else ! 385: chmqSpy = 0; ! 386: } ! 387: ! 388: fAnythingToWatch = (chwndSpy > 0) || (chmqSpy > 0) || ! 389: fProcessAllWindows || fProcessAllFrames; ! 390: DosSemClear( (HSEM)(PULONG)&spyhookSem ); ! 391: ! 392: return(TRUE); ! 393: } ! 394: ! 395: ! 396: /***********************************************************************\ ! 397: * BOOL FAR PASCAL SpyGetQueueList( chmq, rghmq ) ! 398: * ! 399: * Effect: This routine gets the list of queues whose messages we watch. ! 400: * ! 401: * Returns value: TRUE ! 402: \***********************************************************************/ ! 403: SHORT FAR PASCAL SpyGetQueueList( chmq, rghmq ) ! 404: SHORT chmq; ! 405: HMQ FAR *rghmq; ! 406: { ! 407: SHORT i; ! 408: HMQ *phmqT; ! 409: ! 410: DosSemRequest( (HSEM)(PULONG)&spyhookSem, -1L); ! 411: ! 412: if (chmq > chmqSpy) ! 413: chmq = chmqSpy; ! 414: ! 415: phmqT = pahmqSpy; ! 416: ! 417: for (i=0; i < chmq; i++) { ! 418: *rghmq++ = *phmqT++; ! 419: } ! 420: ! 421: DosSemClear( (HSEM)(PULONG)&spyhookSem ); ! 422: ! 423: return(chmq); ! 424: } ! 425: ! 426: ! 427: /***********************************************************************\ ! 428: * BOOL FAR PASCAL SpySetMessageList(UCHAR FAR *prgNewMsgFilter, ! 429: * BOOL fNewDispMsgsNotInList) ! 430: * ! 431: * Effect: This routine sets the list of windows that whose message we watch. 1.1 root 432: * 1.1.1.2 ! root 433: * Returns value: TRUE 1.1 root 434: \***********************************************************************/ 1.1.1.2 ! root 435: BOOL FAR PASCAL SpySetMessageList(prgNewMsgFilter, fNewDispMsgsNotInList) 1.1 root 436: UCHAR FAR *prgNewMsgFilter; 1.1.1.2 ! root 437: BOOL fNewDispMsgsNotInList; 1.1 root 438: { 439: SHORT i; 440: unsigned char *prgb; 441: 442: DosSemRequest( (HSEM)(PULONG)&spyhookSem, -1L); 443: 444: prgb = rgMessageFilter; 445: 1.1.1.2 ! root 446: ! 447: fDispMsgsNotInList = fNewDispMsgsNotInList; ! 448: 1.1 root 449: for (i=0; i < MAXMSGFILTERBYTES; i++) { 450: *prgb++ = *prgNewMsgFilter++; 451: } 452: 453: DosSemClear( (HSEM)(PULONG)&spyhookSem ); 454: 455: return(TRUE); 456: } 457: 458: 1.1.1.2 ! root 459: /***********************************************************************\ ! 460: * BOOL FAR PASCAL SpyFWindowInList (hwnd, fInWindowListOnly) 1.1 root 461: * 462: * Effect: This function checks our current list of windows, and returns 463: * TRUE if the window is in the list, else returns FALSE. 1.1.1.2 ! root 464: * ! 465: * Returns value: TRUE if window is in list. Also, if we are in the special 1.1 root 466: * state we will pass through all frame windows. 467: \***********************************************************************/ 1.1.1.2 ! root 468: BOOL FAR PASCAL SpyFWindowInList (hwnd, fInWindowListOnly) 1.1 root 469: register HWND hwnd; 1.1.1.2 ! root 470: BOOL fInWindowListOnly; 1.1 root 471: { 472: register int i; 473: char szClassName[10]; /* Class name of window */ 474: CLASSINFO classinfo; /* Information about class */ 1.1.1.2 ! root 475: HMQ hmqWindow; /* HMQ of window */ ! 476: HMQ *phmqT; /* Temporary pointer in hmq list */ ! 477: HWND *phwndT; /* Temporary pointer to HWND list */ ! 478: ! 479: phwndT = pahwndSpy; ! 480: for (i=0; i < chwndSpy; i++) { ! 481: if (hwnd == *phwndT++) ! 482: return (TRUE); ! 483: } ! 484: ! 485: /* See if we are restricting to only windows in list */ ! 486: if (fInWindowListOnly) ! 487: return (FALSE); 1.1 root 488: 489: if (fProcessAllWindows) 490: return (TRUE); /* All windows pass through */ 491: 1.1.1.2 ! root 492: /* ! 493: * See if we are watching any message queues ! 494: */ ! 495: if (phmqT = pahmqSpy) { ! 496: hmqWindow = (HMQ)WinQueryWindowULong(hwnd, QWL_HMQ); ! 497: for (i=0; i < chmqSpy; i++) { ! 498: if (*phmqT++ == hmqWindow) ! 499: return (TRUE); ! 500: } 1.1 root 501: } 502: 503: if (fProcessAllFrames) { 504: /* See if frame class */ 505: if (hwnd == NULL) 506: return (TRUE); /* pass queue messages through */ 507: WinQueryClassName(hwnd, sizeof(szClassName), 508: (PSZ)szClassName); 509: WinQueryClassInfo((HAB)NULL, (PSZ)szClassName, 510: &classinfo); 511: if (classinfo.flClassStyle & CS_FRAME) 512: return (TRUE); 513: } 514: 515: return (FALSE); 516: } 517: 518: 1.1.1.2 ! root 519: /***********************************************************************\ 1.1 root 520: * BOOL FAR PASCAL SpyReleaseHook(fZeroQueue) 521: * 522: * Effect: This routine releases the input hook, if it is installed. 523: * 524: * Returns value: TRUE if hook is released, FALSE otherwise. 525: \***********************************************************************/ 526: BOOL FAR PASCAL SpyReleaseHook(fZeroQueue) 527: BOOL fZeroQueue; 528: { 529: BOOL fRet; 530: 531: DosSemRequest ( (HSEM)(PULONG)&spyhookSem, -1L ); 532: 533: if ( habOwner ) { 1.1.1.2 ! root 534: if (SpybHooks & SPYH_INPUT) ! 535: fRet = WinReleaseHook( habOwner, (HMQ)0, HK_INPUT, ! 536: (PFN)SpyInputHook, hmodSpy ); ! 537: ! 538: if (SpybHooks & SPYH_SENDMSG) ! 539: fRet = WinReleaseHook( habOwner, (HMQ)0, HK_SENDMSG, ! 540: (PFN)SpySendMsgHook, hmodSpy ); ! 541: if ( fRet ) { 1.1 root 542: habOwner = (HAB)0; 543: hmqOwner = (HMQ)0; 544: } 545: } 546: 547: /* 548: * When the hook is freed, we want to clear message count out, 549: * make sure any process waiting will abort 550: * Only do this if the Zeroqueu flag was passed 551: */ 552: if (fZeroQueue) { 1.1.1.2 ! root 553: cmsgSpy = 0; 1.1 root 554: imsgWrite = 0; 1.1.1.2 ! root 555: imsgRead = 0; ! 556: if (pahwndSpy != NULL) ! 557: WinFreeMem(hheapSpyHook, (char *)pahwndSpy, ! 558: sizeof(HWND) * chwndSpy); ! 559: pahwndSpy = NULL; 1.1 root 560: chwndSpy = 0; /* Max windows to spy */ 561: fRecording = FALSE; /* Set recording to off */ 1.1.1.2 ! root 562: if (pahmqSpy != NULL) ! 563: WinFreeMem(hheapSpyHook, (char *)pahmqSpy, sizeof(HMQ) * chmqSpy); ! 564: ! 565: pahmqSpy = NULL; ! 566: chmqSpy = 0; ! 567: fAnythingToWatch = FALSE; 1.1 root 568: DosSemClear((HSEM)(PULONG)&spyMsgSem); /* Free any process */ 569: } 570: DosSemClear((HSEM)(PULONG)&spyhookSem); 571: 572: return fRet; 573: } 574: 575: 1.1.1.2 ! root 576: /***********************************************************************\ 1.1 root 577: * BOOL FAR PASCAL SpyHookOnOrOff( fOn) 578: * 579: * Effect: This routine allows the application to turn the hook 580: * processing on or off. 581: * 1.1.1.2 ! root 582: * Returns: TRUE 1.1 root 583: \***********************************************************************/ 584: BOOL FAR PASCAL SpyHookOnOrOff(fOn) 585: BOOL fOn; 586: { 587: DosSemRequest ( (HSEM)(PULONG)&spyhookSem, -1L); 588: 589: fRecording = fOn; 590: 591: DosSemClear( (HSEM)(PULONG)&spyhookSem ); 592: return (TRUE); 593: } 594: 595: 596: 1.1.1.2 ! root 597: /***********************************************************************\ 1.1 root 598: * BOOL FAR PASCAL SpySetAllFrameOpt(fAllFrames) 599: * 600: * Effect: Special state if TRUE will cause the window filter to pass 1.1.1.2 ! root 601: * all frame windows through. This is useful when debugging 1.1 root 602: * interactions between frame windows, when the windows are 603: * net yet created. 604: * 1.1.1.2 ! root 605: * Returns: TRUE 1.1 root 606: \***********************************************************************/ 607: BOOL FAR PASCAL SpySetAllFrameOpt(fAllFrames) 608: BOOL fAllFrames; 609: { 610: fProcessAllFrames = fAllFrames; 1.1.1.2 ! root 611: fAnythingToWatch = (chwndSpy > 0) || (chmqSpy > 0) || ! 612: fProcessAllWindows || fProcessAllFrames; 1.1 root 613: return (TRUE); 614: } 1.1.1.2 ! root 615: ! 616: /***********************************************************************\ 1.1 root 617: * BOOL FAR PASCAL SpySetAllWindowOpt(fAllWindows) 618: * 619: * Effect: Special state if TRUE will cause the window filter to pass 1.1.1.2 ! root 620: * all windows through. This is useful when debugging ! 621: * interactions between all of the windows. 1.1 root 622: * 1.1.1.2 ! root 623: * Returns: TRUE 1.1 root 624: \***********************************************************************/ 625: BOOL FAR PASCAL SpySetAllWindowOpt(fAllWindows) 626: BOOL fAllWindows; 627: { 628: fProcessAllWindows = fAllWindows; 1.1.1.2 ! root 629: fAnythingToWatch = (chwndSpy > 0) || (chmqSpy > 0) || ! 630: fProcessAllWindows || fProcessAllFrames; 1.1 root 631: return (TRUE); 632: } 633: 1.1.1.2 ! root 634: ! 635: /***********************************************************************\ ! 636: * BOOL FAR PASCAL SpySetLNSymbolPID(PID pid, SELECTOR sel); 1.1 root 637: * 1.1.1.2 ! root 638: * ! 639: * Effect: Tell the hook to be on the lookout for a specific PID. ! 640: * If found running in the context of the specified process, we ! 641: * will get the selector information for the specified selector. ! 642: \***********************************************************************/ ! 643: BOOL FAR PASCAL SpySetLNSymbolPID(pid, selector) ! 644: PID pid; ! 645: USHORT selector; ! 646: { ! 647: if (pidLNSpy == 0xffff) { ! 648: selectorLNSpy = selector; ! 649: rcLNSpy = -1; /* Assume error for now */ ! 650: pidLNSpy = pid; /* Save PID to look for */ ! 651: return (TRUE); ! 652: } else ! 653: return (FALSE); ! 654: } ! 655: ! 656: ! 657: ! 658: /***********************************************************************\ ! 659: * VOID SpyCheckPIDForSymbol(VOID) ! 660: * ! 661: * Effect: Only called when we are looking for a symbol ! 662: * ! 663: \***********************************************************************/ ! 664: VOID SpyCheckPIDForSymbol() ! 665: { ! 666: PIDINFO pidinfo; ! 667: ! 668: /* ! 669: * Get the spy semaphore to serialize access and see if we are the ! 670: * correct PID; ! 671: */ ! 672: DosGetPID(&pidinfo); ! 673: if (DosSemRequest((HSEM)(PULONG)&spyhookSem, 100L) != 0) ! 674: return; ! 675: ! 676: if (pidinfo.pid == pidLNSpy) { ! 677: /* ! 678: * We are the correct process, so continue to try go get the ! 679: * symbol information. ! 680: */ ! 681: pidLNSpy = 0xffff; /* reset to not enter again */ ! 682: rcLNSpy = IdentifyCodeSelector( selectorLNSpy, ! 683: (PWHOISINFO)&whoIsLNSpy); ! 684: } ! 685: ! 686: DosSemClear( (HSEM)(PULONG)&spyhookSem ); ! 687: } ! 688: ! 689: ! 690: ! 691: /***********************************************************************\ ! 692: * int FAR PASCAL SpyGetLNSymbolSelector(pwhoinfo) ! 693: * ! 694: * Effect: Get the information about the specified selector. ! 695: * If the specified process has not been executed since the ! 696: * function SpySetLNSymbolPID has been called, it will return -1, ! 697: * else it will return what was returned from IdentifyCodeSelector. ! 698: \***********************************************************************/ ! 699: int FAR PASCAL SpyGetLNSymbolSelector(pwhoIsinfo) ! 700: PWHOISINFO pwhoIsinfo; 1.1 root 701: { 1.1.1.2 ! root 702: *pwhoIsinfo = whoIsLNSpy; ! 703: return (rcLNSpy); ! 704: } ! 705: ! 706: ! 707: ! 708: ! 709: /**********************************************************************\ ! 710: * VOID GrabMsgDataWords (SHORT imsg, UCHAR bMPType) ! 711: * ! 712: * Effect: Gets the next message from the list. ! 713: * ! 714: * if timeout != 0 on message processing threads, problems may occur. ! 715: * if lpqmsg==NULL, this function acts like a query or wait function. ! 716: \***********************************************************************/ ! 717: VOID GrabMsgDataWords(imsg, bMPType) ! 718: SHORT imsg; ! 719: UCHAR bMPType; ! 720: { ! 721: UCHAR bMP1Type; ! 722: UCHAR bMP2Type; ! 723: SHORT cbMPs; ! 724: SHORT cbMP1; ! 725: SHORT cbMP2; ! 726: UCHAR *rgBuf; ! 727: ! 728: /* ! 729: * This function will use the MPType data to know if MP1 and/or MP2 ! 730: * are pointers to any known data, that we want to extract off ! 731: * and save for spy to display later ! 732: */ ! 733: rgqmsgSpy[imsg].bMPType = bMPType; ! 734: bMP1Type = bMPType & MP_MASK; ! 735: cbMPs = cbMP1 = rgqmsgSpy[imsg].cbDataMP1 = acbMPTypes[bMP1Type]; ! 736: ! 737: bMP2Type = (bMPType >> 3) & MP_MASK; ! 738: cbMPs += (cbMP2 = rgqmsgSpy[imsg].cbDataMP2 = acbMPTypes[bMP2Type]); ! 739: ! 740: if (cbMPs > 0) { ! 741: /* Allocate memory to save the data into */ ! 742: rgBuf = rgqmsgSpy[imsg].rgData = WinAllocMem(hheapSpyHook, cbMPs); ! 743: ! 744: if (rgBuf != NULL) { ! 745: /* Copy the data down, Note: if count is 0 will NOP */ ! 746: if (cbMP1) { ! 747: CopyStruct((CHAR FAR *)rgqmsgSpy[imsg].qmsg.mp1, ! 748: rgBuf, cbMP1); ! 749: rgBuf += cbMP1; ! 750: } ! 751: ! 752: if (cbMP2) { ! 753: CopyStruct((CHAR FAR *)rgqmsgSpy[imsg].qmsg.mp2, ! 754: rgBuf, cbMP2); ! 755: } ! 756: } ! 757: ! 758: } else { ! 759: rgqmsgSpy[imsg].rgData = NULL; ! 760: } ! 761: } ! 762: ! 763: /**********************************************************************\ ! 764: * SpyGetNextMessage (lpqmsg, lpBuf, cbBuf, lTimeOut) ! 765: * ! 766: * Effect: Get the next message from the list. ! 767: * if timeout != 0 on message processing threads, problems may occur. ! 768: * if lpqmsg==NULL, this function acts like a query or wait function. ! 769: * ! 770: * Returns: Whether SpyGetNextMessage succeeds or not. ! 771: \***********************************************************************/ ! 772: BOOL FAR PASCAL SpyGetNextMessage(lpqmsg, lpBuf, cbBuf, lTimeOut) ! 773: PQMSGSPY lpqmsg; /* Pointer where the user wants the message stored */ ! 774: PSZ lpBuf; /* pointer to buffer */ ! 775: SHORT cbBuf; /* size of buffer in bytes */ ! 776: LONG lTimeOut; /* Timeout value */ ! 777: { ! 778: ! 779: SHORT cbMsg; /* Count of bytes associated with message */ ! 780: 1.1 root 781: /* Quick escape hatch */ 782: if ((lTimeOut == 0) && (cmsgSpy == 0)) 1.1.1.2 ! root 783: return (FALSE); /* Don't Wait */ 1.1 root 784: 785: /* 1.1.1.2 ! root 786: * Now let's possibly wait for a message 1.1 root 787: */ 788: if (cmsgSpy == 0) { 789: if (DosSemWait((HSEM)(PULONG)&spyMsgSem, lTimeOut) != 0) 790: return (FALSE); /* No messages after timeout */ 791: if (cmsgSpy == 0) 792: return (FALSE); /* Still no messages, return condition */ 793: } 794: 795: /* 796: * If the lpqmsg is NULL, the user is simply asking if there is 1.1.1.2 ! root 797: * a message and/or waiting for the message, so don't extract 1.1 root 798: * the message, but simply return the status. 799: */ 800: if (lpqmsg != NULL) { 801: if (DosSemRequest((HSEM)(PULONG)&spyhookSem, lTimeOut) == 0) { 1.1.1.2 ! root 802: *lpqmsg = rgqmsgSpy[imsgRead]; /* Extract the message */ ! 803: ! 804: cbMsg = rgqmsgSpy[imsgRead].cbDataMP1 ! 805: + rgqmsgSpy[imsgRead].cbDataMP2; ! 806: ! 807: if ((cbMsg > 0) && (lpBuf != NULL)) { ! 808: if (cbMsg < cbBuf) ! 809: cbBuf = cbMsg; /* Number of bytes to copy */ ! 810: CopyStruct(rgqmsgSpy[imsgRead].rgData, lpBuf, cbBuf); ! 811: } ! 812: ! 813: if (cbMsg > 0) ! 814: WinFreeMem(hheapSpyHook, rgqmsgSpy[imsgRead].rgData, cbMsg); ! 815: ! 816: /* Also give the caller any additional information on message */ ! 817: ! 818: imsgRead++; 1.1 root 819: if (imsgRead == MAXMSGCNT) 820: imsgRead = 0; /* Wrap around */ 821: 822: /* 823: * Decrement count of messages, if we go to zero, set 824: * the semaphore, so that the next read will suspend until 825: * the next message 826: */ 827: cmsgSpy--; 828: if (cmsgSpy == 0) 829: DosSemSet((HSEM)(PULONG)&spyMsgSem); 830: 831: DosSemClear( (HSEM)(PULONG)&spyhookSem ); 832: } 833: } 834: 835: return (TRUE); 836: } 837: 1.1.1.2 ! root 838: /***********************************************************************\ 1.1 root 839: * VOID PASCAL Init( hmod ) 1.1.1.2 ! root 840: * ! 841: * Effect: Saves the Spy module handle 1.1 root 842: \***********************************************************************/ 843: VOID PASCAL Init( hmod ) 844: HMODULE hmod; 845: { 1.1.1.2 ! root 846: /* Save the module handle */ 1.1 root 847: hmodSpy = hmod; 848: } 849: 1.1.1.2 ! root 850: /***********************************************************************\ ! 851: * UCHAR GMsgEnableAndType (USHORT msg) 1.1 root 852: * 853: * Effect: 1.1.1.2 ! root 854: * Should the message be processed? 1.1 root 855: * 1.1.1.2 ! root 856: * If the message is out of range ! 857: * or bit is set in message bitmask then return TRUE; 1.1 root 858: \***********************************************************************/ 1.1.1.2 ! root 859: UCHAR GMsgEnableAndType(msg) 1.1 root 860: USHORT msg; 861: { 862: if (msg > MAXMSGFILTER) 1.1.1.2 ! root 863: return ((UCHAR)(fDispMsgsNotInList? MP_ENABLED : 0)); 1.1 root 864: 1.1.1.2 ! root 865: return (rgMessageFilter[msg]); /* One byte per message */ 1.1 root 866: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.