|
|
1.1 ! root 1: /***********************************************************************\ ! 2: * spyhook.C - Spy Global input hook interface library. ! 3: * ! 4: * Created: Microsoft, IBM Corporation 1990 ! 5: * ! 6: * DISCLAIMER OF WARRANTIES. The following [enclosed] code is ! 7: * sample code created by Microsoft Corporation and/or IBM ! 8: * Corporation. This sample code is not part of any standard ! 9: * Microsoft or IBM product and is provided to you solely for ! 10: * the purpose of assisting you in the development of your ! 11: * applications. The code is provided "AS IS", without ! 12: * warranty of any kind. Neither Microsoft nor IBM shall be ! 13: * liable for any damages arising out of your use of the sample ! 14: * code, even if they have been advised of the possibility of ! 15: * such damages. ! 16: * ! 17: * Purpose: This dynlink is needed because global input hooks must ! 18: * reside in a DLL. ! 19: * ! 20: \***********************************************************************/ ! 21: #define INCL_PM ! 22: #define INCL_DOSPROCESS ! 23: #define INCL_DOSMODULEMGR ! 24: #define INCL_DOSSEMAPHORES ! 25: #define INCL_ERRORS ! 26: #include <os2.h> ! 27: #include "spyhk32.h" ! 28: ! 29: // Needed to make a dll link properly ! 30: int _acrtused = 0; ! 31: ! 32: HMTX hmtxSpyHook; /* global semaphore for this module */ ! 33: HEV hevSpyMsg; /* global semaphore for this module */ ! 34: ! 35: HMODULE hmodSpy; /* dynlink module handle */ ! 36: SHORT SpybHooks; /* Whichs Hook do we use */ ! 37: ! 38: HAB habOwner = (HAB)0; /* Hook owner's anchore block */ ! 39: HMQ hmqOwner = (HMQ)0; /* Hook owner's message queue */ ! 40: BOOL fRecording = FALSE; /* Are we recording now? */ ! 41: BOOL fAnythingToWatch = FALSE; /* Is there anything to watch */ ! 42: BOOL fDispMsgsNotInList = TRUE; /* Disp msgs not in list? */ ! 43: ! 44: /* Define array of window handles that we are going to process */ ! 45: BOOL fInitialized = FALSE; ! 46: BOOL fProcessAllFrames = FALSE; /* Are we processing all frame messages */ ! 47: BOOL fProcessAllWindows = FALSE;/* Are we processing all windows */ ! 48: HWND *pahwndSpy = NULL; /* Array of hwnds to spy on, no max here */ ! 49: int chwndSpy = 0; /* Max windows to spy */ ! 50: ! 51: /* Define array of HMQ's to spy on */ ! 52: HMQ *pahmqSpy = NULL; /* HMQ list to spy on */ ! 53: int chmqSpy = 0; /* Count of hmqs we are spying on */ ! 54: ! 55: ! 56: /* Define message filter array */ ! 57: UCHAR rgMessageFilter[MAXMSGFILTERBYTES] = ""; ! 58: UCHAR GMsgEnableAndType(USHORT); /* Is message in message list */ ! 59: VOID GrabMsgDataWords(SHORT, UCHAR); /* Get extra words for message */ ! 60: BOOL CopyStruct(UCHAR *pbSrc, UCHAR *pbDst, SHORT cb); /* Copy bytes */ ! 61: void DebugBreak(void); ! 62: ! 63: /* Define an array of messages to pass to whomever calls us */ ! 64: ! 65: QMSGSPY rgqmsgSpy[MAXMSGCNT]; /* Array of messages to process */ ! 66: SHORT cmsgSpy = 0; /* Count of messages yet to be read */ ! 67: SHORT imsgWrite = 0; /* Index to message to write out */ ! 68: SHORT imsgRead = 0; /* Index to message to read */ ! 69: ! 70: /* Use the Dos Sub allocate functions to make sure to use shared memory */ ! 71: #define HEAPSIZE 16384 /* 16K should be plenty? */ ! 72: PVOID pheapSpyHook; /* Heap to use for Spy Hook DLL */ ! 73: ! 74: PBYTE AllocMem(ULONG cb); ! 75: VOID FreeMem(PBYTE pMem, ULONG cb); ! 76: BOOL EnterSem(ULONG ulWait); ! 77: BOOL LeaveSem(VOID); ! 78: BOOL SignalEvent(VOID); ! 79: ! 80: ! 81: ! 82: SHORT acbMPTypes[MP_MASK+1] = { /* Number of desired bytes to extract */ ! 83: 0, /* Normal fields, no pointers */ ! 84: sizeof(SWP), /* MPT_SWP */ ! 85: sizeof(RECTL), /* MPT_RECTL */ ! 86: 0, /* MPT_WNDPRMS we dont process yet */ ! 87: sizeof(QMSG) /* MPT_QMSG */ ! 88: }; ! 89: ! 90: ! 91: /* Information for geting selector information in diffent PID context */ ! 92: PIT pit = {0xffff, 0, 0L, NULL, 0}; ! 93: USHORT selectorLNSpy = 0; /* Which Selector */ ! 94: VOID SpyCheckPIDForIntercept(VOID); ! 95: ULONG EXPENTRY Init(ULONG hPDLL, HMODULE hmod); ! 96: ! 97: /***********************************************************************\ ! 98: * VOID Init( hmod ) ! 99: * ! 100: * Effect: Saves the Spy module handle ! 101: \***********************************************************************/ ! 102: ULONG EXPENTRY Init(hPDLL, hmod) ! 103: ULONG hPDLL; ! 104: HMODULE hmod; ! 105: { ! 106: /* Save the module handle */ ! 107: hmodSpy = hmod; ! 108: ! 109: return (ULONG)hmodSpy; ! 110: ! 111: /* Unreferenced formal parameters referenced here to prevent compiler ! 112: warning */ ! 113: hPDLL; ! 114: } ! 115: ! 116: ! 117: ! 118: ! 119: /***************************** Exported Function ***********************\ ! 120: * BOOL EXPENTRY SpyInputHook( hab, lpqmsg, fs) ! 121: * HAB hab; ! 122: * PQMSG lpqmsg; ! 123: * USHORT fs; ! 124: * ! 125: * Effect: This is the global input hook procedure. Note that hook ! 126: * procedures can be chained, so we always return FALSE to pass the ! 127: * message to the next guy in chain. ! 128: * ! 129: * Return value: FALSE to pass message to next hook procedure. ! 130: \***********************************************************************/ ! 131: BOOL EXPENTRY SpyInputHook( hab, lpqmsg, fs ) ! 132: HAB hab; ! 133: PQMSG lpqmsg; ! 134: USHORT fs; ! 135: { ! 136: UCHAR bMPType; ! 137: ! 138: /* ! 139: * Check first to see if we are looking for a process symbols ! 140: */ ! 141: if (pit.pid != 0xffff) ! 142: SpyCheckPIDForIntercept(); ! 143: ! 144: /* ! 145: * First check to see if we are processing any hook messages ! 146: */ ! 147: if (!fRecording || !fAnythingToWatch || (cmsgSpy >= MAXMSGCNT)) ! 148: return (FALSE); /* No let the next one have it now */ ! 149: ! 150: /* ! 151: * See if we have any messages to process - Recheck to make sure we ! 152: * Dont overwrite our queue. ! 153: */ ! 154: if (!EnterSem(100L)) { ! 155: DebugBreak(); ! 156: return (FALSE); ! 157: } ! 158: if (cmsgSpy < MAXMSGCNT) { ! 159: if (SpyFWindowInList(lpqmsg->hwnd, FALSE) && ! 160: (bMPType = GMsgEnableAndType(lpqmsg->msg))) { ! 161: rgqmsgSpy[imsgWrite].fs = fs; /* Save the flags */ ! 162: rgqmsgSpy[imsgWrite].qmsg = *lpqmsg; /* Save the message */ ! 163: ! 164: GrabMsgDataWords(imsgWrite, bMPType); ! 165: imsgWrite++; ! 166: ! 167: if (imsgWrite == MAXMSGCNT) ! 168: imsgWrite = 0; /* Wrap around */ ! 169: cmsgSpy++; ! 170: SignalEvent(); ! 171: } ! 172: } ! 173: ! 174: LeaveSem(); ! 175: return FALSE; /* Let system take normal action. */ ! 176: ! 177: /* Unreferenced formal parameters referenced here to prevent compiler ! 178: warning */ ! 179: hab; ! 180: ! 181: } ! 182: ! 183: ! 184: /***************************** Exported Function ***********************\ ! 185: * BOOL EXPENTRY SpySendMsgHook( hab, lpsmh, fInterTask) ! 186: * HAB hab; ! 187: * PQMSG lpqmsg; ! 188: * ! 189: * Effect: This is the global input hook procedure. Note that hook ! 190: * procedures can be chained, so we always return FALSE to pass the ! 191: * message to the next guy in chain. ! 192: * ! 193: * Return value: FALSE to pass message to next hook procedure. ! 194: \***********************************************************************/ ! 195: BOOL EXPENTRY SpySendMsgHook( hab, lpsmh, fInterTask ) ! 196: HAB hab; ! 197: PSMHSTRUCT lpsmh; ! 198: BOOL fInterTask; ! 199: { ! 200: UCHAR bMPType; ! 201: PPIB ppib; ! 202: PTIB ptib; ! 203: ! 204: /* ! 205: * Check first to see if we are looking for a process symbols ! 206: */ ! 207: if (pit.pid != 0xffff) ! 208: SpyCheckPIDForIntercept(); ! 209: ! 210: /* ! 211: * First check to see if we are processing any hook messages ! 212: */ ! 213: if (!fRecording || !fAnythingToWatch || (cmsgSpy >= MAXMSGCNT)) ! 214: return (FALSE); /* No let the next one have it now */ ! 215: ! 216: /* ! 217: * See if we have any messages to process ! 218: */ ! 219: if (!EnterSem(100L)) { ! 220: DebugBreak(); ! 221: return (FALSE); ! 222: } ! 223: /* Make sure no one got in by mistake */ ! 224: if (cmsgSpy < MAXMSGCNT) { ! 225: if (SpyFWindowInList(lpsmh->hwnd, FALSE) && ! 226: (bMPType = GMsgEnableAndType(lpsmh->msg))) { ! 227: /* ! 228: * Store out message, must move pieces seperatly ! 229: */ ! 230: rgqmsgSpy[imsgWrite].fs = fInterTask; ! 231: rgqmsgSpy[imsgWrite].qmsg.hwnd = lpsmh->hwnd; ! 232: rgqmsgSpy[imsgWrite].qmsg.msg = lpsmh->msg; ! 233: rgqmsgSpy[imsgWrite].qmsg.mp1 = lpsmh->mp1; ! 234: rgqmsgSpy[imsgWrite].qmsg.mp2 = lpsmh->mp2; ! 235: rgqmsgSpy[imsgWrite].qmsg.time = (ULONG)-1; ! 236: rgqmsgSpy[imsgWrite].qmsg.ptl.x = 0; ! 237: rgqmsgSpy[imsgWrite].qmsg.ptl.y = 0; ! 238: ! 239: GrabMsgDataWords(imsgWrite, bMPType); ! 240: ! 241: /* Now get the PID/TID info, and do the stack backtrace */ ! 242: DosGetThreadInfo(&ptib, &ppib); ! 243: rgqmsgSpy[imsgWrite].pidSend = ppib->pib_ulpid; ! 244: rgqmsgSpy[imsgWrite].tidSend = ptib->tib_ultid; ! 245: ! 246: imsgWrite++; ! 247: if (imsgWrite == MAXMSGCNT) ! 248: imsgWrite = 0; /* Wrap around */ ! 249: cmsgSpy++; ! 250: SignalEvent(); ! 251: } ! 252: } ! 253: ! 254: LeaveSem(); ! 255: return FALSE; /* Let system take normal action. */ ! 256: ! 257: /* Unreferenced formal parameters referenced here to prevent compiler ! 258: warning */ ! 259: hab; ! 260: ! 261: } ! 262: ! 263: ! 264: /*************************** Public Function ***************************\ ! 265: * BOOL EXPENTRY SpyInstallHook( hab, hmq, fSendMessage, bHooks) ! 266: * ! 267: * Effect: This routine installs a system-wide HK_INPUT hook. The hab ! 268: * hmq are remembered for message posting. Note that we only allow ! 269: * one input hook to be installed through this routine, but other ! 270: * apps may call WinSetHook directly. ! 271: * ! 272: * Returns value: TRUE if hook installed successfully, FALSE otherwise. ! 273: \***********************************************************************/ ! 274: BOOL EXPENTRY SpyInstallHook( hab, hmq, bHooks ) ! 275: HAB hab; ! 276: HMQ hmq; ! 277: USHORT bHooks; ! 278: { ! 279: BOOL fRet; ! 280: ULONG ulPostCt; ! 281: ! 282: EnterSem(-1L); ! 283: ! 284: ! 285: /* ! 286: * Look at hook index if == HK_INPUT Install a system-wide input hook. ! 287: * else set system wide SENDMSG hook ! 288: */ ! 289: SpybHooks = bHooks; ! 290: if (SpybHooks & SPYH_INPUT) ! 291: fRet = WinSetHook( hab, (HMQ)0, HK_INPUT, (PFN)SpyInputHook, ! 292: hmodSpy ); ! 293: ! 294: if (SpybHooks & SPYH_SENDMSG) ! 295: fRet = WinSetHook( hab, (HMQ)0, HK_SENDMSG, (PFN)SpySendMsgHook, ! 296: hmodSpy ); ! 297: if (fRet) { ! 298: habOwner = hab; ! 299: hmqOwner = hmq; ! 300: } ! 301: ! 302: DosResetEventSem(hevSpyMsg, &ulPostCt); /* Init, no messages avail */ ! 303: LeaveSem(); ! 304: ! 305: return fRet; ! 306: } ! 307: ! 308: ! 309: ! 310: /*************************** Public Function ***************************\ ! 311: * BOOL EXPENTRY SpySetWindowList( chwnd, rghwnd) ! 312: * ! 313: * Effect: This routine sets the list of window that we are interested ! 314: * in watching the messages for. ! 315: * ! 316: * Returns value: TRUE ! 317: \***********************************************************************/ ! 318: BOOL EXPENTRY SpySetWindowList( chwnd, rghwnd ) ! 319: SHORT chwnd; ! 320: HWND *rghwnd; ! 321: { ! 322: SHORT i; ! 323: HWND *phwndT; ! 324: ! 325: EnterSem(-1L); ! 326: ! 327: if (pahwndSpy) { ! 328: FreeMem((char *)pahwndSpy, sizeof(HWND) * chwndSpy); ! 329: pahwndSpy = NULL; ! 330: } ! 331: ! 332: ! 333: chwndSpy = chwnd; ! 334: ! 335: if (chwndSpy > 0 ) { ! 336: ! 337: phwndT = pahwndSpy = (HWND *)AllocMem(sizeof(HWND) * chwndSpy); ! 338: ! 339: if (phwndT != NULL) { ! 340: for (i=0; i < chwnd; i++) { ! 341: *phwndT++ = *rghwnd++; ! 342: } ! 343: } else ! 344: chwndSpy = 0; ! 345: } ! 346: ! 347: fAnythingToWatch = (chwndSpy > 0) || (chmqSpy > 0) || ! 348: fProcessAllWindows || fProcessAllFrames; ! 349: ! 350: LeaveSem(); ! 351: return(TRUE); ! 352: } ! 353: ! 354: ! 355: /*************************** Public Function ***************************\ ! 356: * BOOL EXPENTRY SpyGetWindowList( chwnd, rghwnd) ! 357: * ! 358: * Effect: This routine sets the list of window that we are interested ! 359: * in watching the messages for. ! 360: * ! 361: * Returns value: TRUE ! 362: \***********************************************************************/ ! 363: SHORT EXPENTRY SpyGetWindowList( chwnd, rghwnd ) ! 364: SHORT chwnd; ! 365: HWND *rghwnd; ! 366: { ! 367: SHORT i; ! 368: HWND *phwndT; ! 369: ! 370: EnterSem(-1L); ! 371: ! 372: if (chwnd > chwndSpy) ! 373: chwnd = chwndSpy; ! 374: ! 375: phwndT = pahwndSpy; ! 376: for (i=0; i < chwnd; i++) { ! 377: *rghwnd++ = *phwndT++; ! 378: } ! 379: ! 380: LeaveSem(); ! 381: ! 382: return(chwnd); ! 383: } ! 384: ! 385: ! 386: ! 387: ! 388: /*************************** Public Function ***************************\ ! 389: * BOOL EXPENTRY SpySetQueueList( chmq, rghmq) ! 390: * ! 391: * Effect: This routine sets the list of Queue that we are interested ! 392: * in watching the messages for. ! 393: * ! 394: * Returns value: TRUE ! 395: \***********************************************************************/ ! 396: BOOL EXPENTRY SpySetQueueList( chmq, rghmq ) ! 397: SHORT chmq; ! 398: HMQ *rghmq; ! 399: { ! 400: SHORT i; ! 401: HMQ *phmqT; ! 402: ! 403: EnterSem(-1L); ! 404: ! 405: /* ! 406: * If we previously had a list of HMQs to spy on, free the old list ! 407: * now ! 408: */ ! 409: if (pahmqSpy != NULL) { ! 410: FreeMem((char *)pahmqSpy, sizeof(HMQ) * chmqSpy); ! 411: pahmqSpy = NULL; ! 412: } ! 413: ! 414: chmqSpy = chmq; ! 415: ! 416: if (chmqSpy > 0) { ! 417: phmqT = pahmqSpy = (HMQ *)AllocMem(sizeof(HMQ) * chmqSpy); ! 418: ! 419: if (phmqT != NULL) { ! 420: for (i=0; i < chmq; i++) { ! 421: *phmqT++ = *rghmq++; ! 422: } ! 423: } else ! 424: chmqSpy = 0; ! 425: } ! 426: ! 427: fAnythingToWatch = (chwndSpy > 0) || (chmqSpy > 0) || ! 428: fProcessAllWindows || fProcessAllFrames; ! 429: LeaveSem(); ! 430: ! 431: return(TRUE); ! 432: } ! 433: ! 434: ! 435: /*************************** Public Function ***************************\ ! 436: * BOOL EXPENTRY SpyGetQueueList( chmq, rghmq) ! 437: * ! 438: * Effect: This routine sets the list of Queue that we are interested ! 439: * in watching the messages for. ! 440: * ! 441: * Returns value: TRUE ! 442: \***********************************************************************/ ! 443: SHORT EXPENTRY SpyGetQueueList( chmq, rghmq ) ! 444: SHORT chmq; ! 445: HMQ *rghmq; ! 446: { ! 447: SHORT i; ! 448: HMQ *phmqT; ! 449: ! 450: EnterSem(-1L); ! 451: ! 452: if (chmq > chmqSpy) ! 453: chmq = chmqSpy; ! 454: ! 455: phmqT = pahmqSpy; ! 456: ! 457: for (i=0; i < chmq; i++) { ! 458: *rghmq++ = *phmqT++; ! 459: } ! 460: ! 461: LeaveSem(); ! 462: ! 463: return(chmq); ! 464: } ! 465: ! 466: ! 467: /*************************** Public Function ***************************\ ! 468: * BOOL EXPENTRY SpySetMessageList(UCHAR *prgNewMsgFilter, ! 469: * BOOL fNewDispMsgsNotInList) ! 470: * ! 471: * Effect: This routine sets the list of window that we are interested ! 472: * in watching the messages for. ! 473: * ! 474: * Returns value: TRUE ! 475: \***********************************************************************/ ! 476: BOOL EXPENTRY SpySetMessageList(prgNewMsgFilter, fNewDispMsgsNotInList) ! 477: UCHAR *prgNewMsgFilter; ! 478: BOOL fNewDispMsgsNotInList; ! 479: { ! 480: SHORT i; ! 481: unsigned char *prgb; ! 482: ! 483: EnterSem(-1L); ! 484: ! 485: prgb = rgMessageFilter; ! 486: ! 487: ! 488: fDispMsgsNotInList = fNewDispMsgsNotInList; ! 489: ! 490: for (i=0; i < MAXMSGFILTERBYTES; i++) { ! 491: *prgb++ = *prgNewMsgFilter++; ! 492: } ! 493: ! 494: LeaveSem(); ! 495: ! 496: return(TRUE); ! 497: } ! 498: ! 499: ! 500: /*************************** Public Function ***************************\ ! 501: * BOOL EXPENTRY SpyFWindowInList (hwnd, fInWindowListOnly) ! 502: * ! 503: * Effect: This function checks our current list of windows, and returns ! 504: * TRUE if the window is in the list, else returns FALSE. ! 505: * Returns value: TRUE if window is in list. Also if We are in the special ! 506: * state we will pass through all frame windows. ! 507: \***********************************************************************/ ! 508: BOOL EXPENTRY SpyFWindowInList (hwnd, fInWindowListOnly) ! 509: register HWND hwnd; ! 510: BOOL fInWindowListOnly; ! 511: { ! 512: register int i; ! 513: char szClassName[10]; /* Class name of window */ ! 514: CLASSINFO classinfo; /* Information about class */ ! 515: HMQ hmqWindow; /* HMQ of window */ ! 516: HMQ *phmqT; /* Temporary pointer in hmq list */ ! 517: HWND *phwndT; /* Temporary pointer to HWND list */ ! 518: PPIB ppib; ! 519: PTIB ptib; ! 520: MQINFO mqinfo; /* Queue info */ ! 521: ! 522: ! 523: ! 524: phwndT = pahwndSpy; ! 525: for (i=0; i < chwndSpy; i++) { ! 526: if (hwnd == *phwndT++) ! 527: return (TRUE); ! 528: } ! 529: ! 530: /* See if we are restricting to only windows in list */ ! 531: if (fInWindowListOnly) ! 532: return (FALSE); ! 533: ! 534: if (fProcessAllWindows) ! 535: return (TRUE); /* All windows pass through */ ! 536: ! 537: /* ! 538: * See if we are watching any message queues ! 539: */ ! 540: if (phmqT = pahmqSpy) { ! 541: if (hwnd != NULL) { ! 542: /* ! 543: * Sent to specific window First see if the user has specified ! 544: * that the want all messages that are sent to this message ! 545: * queue ! 546: */ ! 547: hmqWindow = (HMQ)WinQueryWindowULong(hwnd, QWL_HMQ); ! 548: for (i=0; i < chmqSpy; i++) { ! 549: if (*phmqT++ == hmqWindow) ! 550: return (TRUE); ! 551: } ! 552: } else { ! 553: // For NULL window handle, see if the current process has HMQ ! 554: /* ! 555: * Null Window handle, so instead we need to go through the ! 556: * list of queues we are watching and see if their PID and TID ! 557: * matches our current thread. ! 558: */ ! 559: DosGetThreadInfo(&ptib, &ppib); ! 560: for (i=0; i < chmqSpy; i++) { ! 561: if (WinQueryQueueInfo(*phmqT, &mqinfo, sizeof(mqinfo))) { ! 562: if ((mqinfo.pid == ppib->pib_ulpid) && ! 563: (mqinfo.tid == ptib->tib_ultid)) ! 564: return (TRUE); // Yes we want this queue! ! 565: ! 566: } ! 567: phmqT++; ! 568: } ! 569: } ! 570: } ! 571: ! 572: if (fProcessAllFrames) { ! 573: /* See if frame class */ ! 574: if (hwnd == NULL) ! 575: return (TRUE); /* pass queue messages through */ ! 576: WinQueryClassName(hwnd, sizeof(szClassName), ! 577: (PSZ)szClassName); ! 578: WinQueryClassInfo((HAB)NULL, (PSZ)szClassName, ! 579: &classinfo); ! 580: if (classinfo.flClassStyle & CS_FRAME) ! 581: return (TRUE); ! 582: } ! 583: ! 584: return (FALSE); ! 585: } ! 586: ! 587: ! 588: /*************************** Public Function ***************************\ ! 589: * BOOL EXPENTRY SpyReleaseHook(fZeroQueue) ! 590: * ! 591: * Effect: This routine releases the input hook, if it is installed. ! 592: * ! 593: * Returns value: TRUE if hook is released, FALSE otherwise. ! 594: \***********************************************************************/ ! 595: BOOL EXPENTRY SpyReleaseHook(fZeroQueue) ! 596: BOOL fZeroQueue; ! 597: { ! 598: BOOL fRet; ! 599: ! 600: EnterSem(-1L); ! 601: ! 602: if ( habOwner ) { ! 603: if (SpybHooks & SPYH_INPUT) ! 604: fRet = WinReleaseHook( habOwner, (HMQ)0, HK_INPUT, ! 605: (PFN)SpyInputHook, hmodSpy ); ! 606: ! 607: if (SpybHooks & SPYH_SENDMSG) ! 608: fRet = WinReleaseHook( habOwner, (HMQ)0, HK_SENDMSG, ! 609: (PFN)SpySendMsgHook, hmodSpy ); ! 610: if ( fRet ) { ! 611: habOwner = (HAB)0; ! 612: hmqOwner = (HMQ)0; ! 613: } ! 614: } ! 615: ! 616: /* ! 617: * When the hook is freed, we want to clear message count out, ! 618: * make sure any process waiting will abort ! 619: * Only do this if the Zeroqueu flag was passed ! 620: */ ! 621: if (fZeroQueue) { ! 622: cmsgSpy = 0; ! 623: imsgWrite = 0; ! 624: imsgRead = 0; ! 625: if (pahwndSpy != NULL) ! 626: FreeMem((char *)pahwndSpy, sizeof(HWND) * chwndSpy); ! 627: pahwndSpy = NULL; ! 628: chwndSpy = 0; /* Max windows to spy */ ! 629: fRecording = FALSE; /* Set recording to off */ ! 630: if (pahmqSpy != NULL) ! 631: FreeMem((char *)pahmqSpy, sizeof(HMQ) * chmqSpy); ! 632: ! 633: pahmqSpy = NULL; ! 634: chmqSpy = 0; ! 635: fAnythingToWatch = FALSE; ! 636: SignalEvent(); /* Free any process */ ! 637: } ! 638: LeaveSem(); ! 639: ! 640: return fRet; ! 641: } ! 642: ! 643: ! 644: /*************************** Public Function ***************************\ ! 645: * BOOL EXPENTRY SpyHookOnOrOff( fOn) ! 646: * ! 647: * Effect: This routine allows the application to turn the hook ! 648: * processing on or off. ! 649: * ! 650: * Returns value: ! 651: \***********************************************************************/ ! 652: BOOL EXPENTRY SpyHookOnOrOff(fOn) ! 653: BOOL fOn; ! 654: { ! 655: EnterSem(-1L); ! 656: ! 657: fRecording = fOn; ! 658: ! 659: LeaveSem(); ! 660: return (TRUE); ! 661: } ! 662: ! 663: ! 664: ! 665: /*************************** Public Function ***************************\ ! 666: * BOOL EXPENTRY SpySetAllFrameOpt(fAllFrames) ! 667: * ! 668: * Effect: Special state if TRUE will cause the window filter to pass ! 669: * all frame windows through. This is usefull when debuging ! 670: * interactions between frame windows, when the windows are ! 671: * net yet created. ! 672: * ! 673: * Returns value: ! 674: \***********************************************************************/ ! 675: BOOL EXPENTRY SpySetAllFrameOpt(fAllFrames) ! 676: BOOL fAllFrames; ! 677: { ! 678: fProcessAllFrames = fAllFrames; ! 679: fAnythingToWatch = (chwndSpy > 0) || (chmqSpy > 0) || ! 680: fProcessAllWindows || fProcessAllFrames; ! 681: return (TRUE); ! 682: } ! 683: ! 684: /*************************** Public Function ***************************\ ! 685: * BOOL EXPENTRY SpySetAllWindowOpt(fAllWindows) ! 686: * ! 687: * Effect: Special state if TRUE will cause the window filter to pass ! 688: * all windows through. This is usefull when debuging ! 689: * interactions between all of the windows ! 690: * ! 691: * Returns value: ! 692: \***********************************************************************/ ! 693: BOOL EXPENTRY SpySetAllWindowOpt(fAllWindows) ! 694: BOOL fAllWindows; ! 695: { ! 696: fProcessAllWindows = fAllWindows; ! 697: fAnythingToWatch = (chwndSpy > 0) || (chmqSpy > 0) || ! 698: fProcessAllWindows || fProcessAllFrames; ! 699: return (TRUE); ! 700: } ! 701: ! 702: ! 703: /*************************** Public Function ***************************\ ! 704: * BOOL EXPENTRY SpySetPIDIntercept(PID pid, USHORT usPIT, ULONG ulInfo); ! 705: * ! 706: * ! 707: * Effect: Hack to tell the hook to be on the look out for a specific ! 708: * PID. If it finds it is running in the context of the specified ! 709: * process, it will get the selector information for the specified ! 710: * selector. ! 711: * ! 712: * Returns value: ! 713: \***********************************************************************/ ! 714: BOOL EXPENTRY SpySetPIDIntercept(pid, usPIT, ulInfo) ! 715: PID pid; ! 716: USHORT usPIT; ! 717: ULONG ulInfo; ! 718: { ! 719: if (pit.pid == 0xffff) { ! 720: pit.pid = pid; ! 721: pit.usPIT = usPIT; ! 722: pit.ulInfo = ulInfo; ! 723: return (TRUE); ! 724: } else ! 725: return (FALSE); ! 726: } ! 727: ! 728: ! 729: ! 730: /***************************** Exported Function ***********************\ ! 731: * VOID SpyCheckPIDForIntercept(VOID) ! 732: * ! 733: * Effect: Only called when we are looking for a symbol ! 734: * ! 735: \***********************************************************************/ ! 736: VOID SpyCheckPIDForIntercept() ! 737: { ! 738: PPIB ppib; ! 739: PTIB ptib; ! 740: ! 741: /* ! 742: * Get the spy semaphore to serialize access and see if we are the ! 743: * correct PID; ! 744: */ ! 745: DosGetThreadInfo(&ptib, &ppib); ! 746: if (!EnterSem(100L)) ! 747: return; ! 748: ! 749: if (ppib->pib_ulpid == pit.pid) { ! 750: /* ! 751: * We are the correct process, so continue to try go get the ! 752: * symbol information. ! 753: */ ! 754: pit.pid = 0xffff; /* reset to not enter again */ ! 755: ! 756: switch (pit.usPIT) { ! 757: break; ! 758: case PIT_ACCEL: ! 759: // Allocate memory for the Accel table. ! 760: pit.cbData = WinCopyAccelTable((HACCEL)pit.ulInfo, ! 761: (PACCELTABLE)NULL, 0); ! 762: pit.pvoidData = AllocMem(pit.cbData); ! 763: if (pit.pvoidData == NULL) { ! 764: pit.cbData = 0; ! 765: break; ! 766: } ! 767: WinCopyAccelTable((HACCEL)pit.ulInfo, ! 768: (PACCELTABLE)pit.pvoidData, pit.cbData); ! 769: break; ! 770: } ! 771: } ! 772: ! 773: LeaveSem(); ! 774: } ! 775: ! 776: ! 777: ! 778: /*************************** Public Function ***************************\ ! 779: * int EXPENTRY SpyGetLNSymbolSelector(pwhoinfo) ! 780: * ! 781: * Effect: Hack to get the information about the specified selector. ! 782: * If the specified process has not been executed since the ! 783: * function SpySetPIDIntercept has been called, it will return -1, ! 784: * else it will return what was returned from IdentifyCodeSelector. ! 785: * ! 786: * Returns value: ! 787: \***********************************************************************/ ! 788: USHORT EXPENTRY SpyGetPIDInterceptData(pvoidBuffer, cbBuffer, pmresult) ! 789: PVOID pvoidBuffer; ! 790: USHORT cbBuffer; ! 791: PMRESULT pmresult; ! 792: { ! 793: if (pvoidBuffer != NULL) { ! 794: if (pit.pvoidData != NULL) { ! 795: if (cbBuffer > pit.cbData) ! 796: cbBuffer = pit.cbData; ! 797: CopyStruct(pit.pvoidData, pvoidBuffer, cbBuffer); ! 798: FreeMem(pit.pvoidData, pit.cbData); ! 799: pit.pvoidData = NULL; ! 800: } ! 801: } ! 802: ! 803: if (pmresult != NULL) ! 804: *pmresult = pit.mresult; ! 805: ! 806: return (pit.cbData); ! 807: } ! 808: ! 809: ! 810: ! 811: ! 812: /*************************** Public Function **************************\ ! 813: * VOID GrabMsgDataWords (SHORT imsg, UCHAR bMPType) ! 814: * ! 815: * Effect: ! 816: * Get the next message from the list - if timeout != 0 an message ! 817: * processing threads, you may have problems, - If lpqmsg==NULL, this ! 818: * function acts like a query or wait function. ! 819: * ! 820: * Returns value: ! 821: \***********************************************************************/ ! 822: VOID GrabMsgDataWords(imsg, bMPType) ! 823: SHORT imsg; ! 824: UCHAR bMPType; ! 825: { ! 826: UCHAR bMP1Type; ! 827: UCHAR bMP2Type; ! 828: SHORT cbMPs; ! 829: SHORT cbMP1; ! 830: SHORT cbMP2; ! 831: UCHAR *rgBuf; ! 832: ! 833: /* ! 834: * This function will use the MPType data to know if MP1 and/or MP2 ! 835: * are pointers to any known data, that we want to extract off ! 836: * and save for spy to display later ! 837: */ ! 838: rgqmsgSpy[imsg].bMPType = bMPType; ! 839: bMP1Type = bMPType & MP_MASK; ! 840: cbMPs = cbMP1 = rgqmsgSpy[imsg].cbDataMP1 = acbMPTypes[bMP1Type]; ! 841: ! 842: bMP2Type = (bMPType >> 3) & MP_MASK; ! 843: cbMPs += (cbMP2 = rgqmsgSpy[imsg].cbDataMP2 = acbMPTypes[bMP2Type]); ! 844: ! 845: if (cbMPs > 0) { ! 846: /* Allocate memory to save the data into */ ! 847: rgBuf = rgqmsgSpy[imsg].rgData = AllocMem(cbMPs); ! 848: ! 849: if (rgBuf != NULL) { ! 850: /* Copy the data down, Note: if count is 0 will NOP */ ! 851: if (cbMP1) { ! 852: rgqmsgSpy[imsg].fMP1Valid = CopyStruct( ! 853: (CHAR *)rgqmsgSpy[imsg].qmsg.mp1, rgBuf, cbMP1); ! 854: rgBuf += cbMP1; ! 855: } ! 856: ! 857: if (cbMP2) { ! 858: rgqmsgSpy[imsg].fMP2Valid = CopyStruct( ! 859: (CHAR *)rgqmsgSpy[imsg].qmsg.mp2, rgBuf, cbMP2); ! 860: } ! 861: } ! 862: ! 863: } else { ! 864: rgqmsgSpy[imsg].rgData = NULL; ! 865: } ! 866: } ! 867: ! 868: ! 869: ! 870: ! 871: ! 872: ! 873: /*************************** Public Function **************************\ ! 874: * SpyGetNextMessage (lpqmsg, lpBuf, cbBuf, lTimeOut) ! 875: * ! 876: * Effect: ! 877: * Get the next message from the list - if timeout != 0 an message ! 878: * processing threads, you may have problems, - If lpqmsg==NULL, this ! 879: * function acts like a query or wait function. ! 880: * ! 881: * Returns value: ! 882: \***********************************************************************/ ! 883: BOOL EXPENTRY SpyGetNextMessage(lpqmsg, lpBuf, cbBuf, lTimeOut) ! 884: PQMSGSPY lpqmsg; /* Pointer where the user wants the message stored */ ! 885: PSZ lpBuf; /* pointer to buffer */ ! 886: SHORT cbBuf; /* size of buffer in bytes */ ! 887: LONG lTimeOut; /* Timeout value */ ! 888: { ! 889: ! 890: SHORT cbMsg; /* Count of bytes associated with message */ ! 891: ULONG ulPostCt; /* Count of posts to semaphore before reset */ ! 892: ! 893: /* Quick escape hatch */ ! 894: if ((lTimeOut == 0) && (cmsgSpy == 0)) ! 895: return (FALSE); /* Dont Wait */ ! 896: ! 897: /* ! 898: * Now lets possibly wait for a message ! 899: */ ! 900: if (cmsgSpy == 0) { ! 901: if (DosWaitEventSem(hevSpyMsg, lTimeOut) != 0) ! 902: return (FALSE); /* No messages after timeout */ ! 903: if (cmsgSpy == 0) ! 904: return (FALSE); /* Still no messages, return condition */ ! 905: } ! 906: ! 907: /* ! 908: * If the lpqmsg is NULL, the user is simply asking if there is ! 909: * a message and/or waiting for the message, so dont extract ! 910: * the message, but simply return the status. ! 911: */ ! 912: if (lpqmsg != NULL) { ! 913: if (DosRequestMutexSem(hmtxSpyHook, lTimeOut) == 0) { ! 914: *lpqmsg = rgqmsgSpy[imsgRead]; /* Extract the message */ ! 915: ! 916: cbMsg = rgqmsgSpy[imsgRead].cbDataMP1 ! 917: + rgqmsgSpy[imsgRead].cbDataMP2; ! 918: ! 919: if ((cbMsg > 0) && (lpBuf != NULL)) { ! 920: if (cbMsg < cbBuf) ! 921: cbBuf = cbMsg; /* Number of bytes to copy */ ! 922: CopyStruct(rgqmsgSpy[imsgRead].rgData, lpBuf, cbBuf); ! 923: } ! 924: ! 925: if (cbMsg > 0) ! 926: FreeMem(rgqmsgSpy[imsgRead].rgData, cbMsg); ! 927: ! 928: /* Also give the caller any additional information on message */ ! 929: ! 930: imsgRead++; ! 931: if (imsgRead == MAXMSGCNT) ! 932: imsgRead = 0; /* Wrap around */ ! 933: ! 934: /* ! 935: * Decrement count of messages, if we go to zero, set ! 936: * the semaphore, so that the next read will suspend until ! 937: * the next message ! 938: */ ! 939: cmsgSpy--; ! 940: if (cmsgSpy == 0) ! 941: DosResetEventSem(hevSpyMsg, &ulPostCt); ! 942: ! 943: LeaveSem(); ! 944: } ! 945: } ! 946: ! 947: return (TRUE); ! 948: } ! 949: ! 950: ! 951: ! 952: ! 953: /*************************** Private Function **************************\ ! 954: * VOID SpyInitializeHookt(void) ! 955: * ! 956: * Effect: ! 957: * ! 958: * ! 959: * Returns value: ! 960: \***********************************************************************/ ! 961: BOOL EXPENTRY SpyInitializeHook (VOID) ! 962: { ! 963: ! 964: if (fInitialized) { ! 965: return (TRUE); ! 966: } ! 967: ! 968: fInitialized = TRUE; ! 969: ! 970: /* Make an event semaphore to signal spy program with */ ! 971: DosCreateMutexSem(NULL, &hmtxSpyHook, DC_SEM_SHARED, FALSE); ! 972: DosCreateEventSem(NULL, &hevSpyMsg, DC_SEM_SHARED, FALSE); ! 973: ! 974: /* Initialize our local heap */ ! 975: DosAllocSharedMem(&pheapSpyHook, NULL, HEAPSIZE, ! 976: PAG_COMMIT | PAG_READ | PAG_WRITE | OBJ_GETTABLE); ! 977: DosSubSet((PVOID)pheapSpyHook, 1, HEAPSIZE); ! 978: ! 979: /* Get the module handle. */ ! 980: return TRUE; ! 981: ! 982: } ! 983: ! 984: ! 985: /*************************** Private Function **************************\ ! 986: * VOID SpyTerminateHook( ) ! 987: * ! 988: * Effect: ! 989: * ! 990: * ! 991: * Returns value: ! 992: \***********************************************************************/ ! 993: BOOL EXPENTRY SpyTerminateHook (VOID) ! 994: { ! 995: ! 996: ! 997: if (!fInitialized) { ! 998: return (FALSE); ! 999: } ! 1000: ! 1001: fInitialized = FALSE; ! 1002: ! 1003: /* Close the semaphore off now */ ! 1004: DosCloseMutexSem(hmtxSpyHook); ! 1005: DosCloseEventSem(hevSpyMsg); ! 1006: ! 1007: /* Also need to free memory */ ! 1008: ! 1009: ! 1010: } ! 1011: ! 1012: ! 1013: /*************************** Private Function **************************\ ! 1014: * UCHAR GMsgEnableAndType (USHORT msg) ! 1015: * ! 1016: * Effect: ! 1017: * Should the message be processed. If the message is out of range, ! 1018: * or bit is set in message bitmask return TRUE ! 1019: * ! 1020: * Returns value: ! 1021: * BOOL ! 1022: \***********************************************************************/ ! 1023: UCHAR GMsgEnableAndType(msg) ! 1024: USHORT msg; ! 1025: { ! 1026: if (msg > MAXMSGFILTER) ! 1027: return ((UCHAR)(fDispMsgsNotInList? MP_ENABLED : 0)); ! 1028: ! 1029: return (rgMessageFilter[msg]); /* One byte per message */ ! 1030: } ! 1031: ! 1032: ! 1033: /*************************** Private Function **************************\ ! 1034: * PBYTE AllocMem (ULONG cb) ! 1035: * ! 1036: * Effect: ! 1037: * Allocates memory from our local heap, and hides that we are no longer ! 1038: * calling WinAllocMem. ! 1039: * ! 1040: * Returns value: ! 1041: * PBYTE ! 1042: \***********************************************************************/ ! 1043: PBYTE AllocMem(ULONG cb) ! 1044: { ! 1045: PVOID pbT; ! 1046: ULONG ulCb; ! 1047: ULONG ulFlag; ! 1048: ! 1049: if (DosQueryMem(pheapSpyHook, &ulCb, &ulFlag)) { ! 1050: if (DosGetSharedMem(pheapSpyHook, PAG_READ | PAG_WRITE)) { ! 1051: DebugBreak; ! 1052: return (NULL); ! 1053: } ! 1054: } ! 1055: ! 1056: if (DosSubAlloc((PVOID)pheapSpyHook, (PPVOID)&pbT, cb)) ! 1057: return(NULL); ! 1058: ! 1059: return(pbT); ! 1060: } ! 1061: ! 1062: ! 1063: /*************************** Private Function **************************\ ! 1064: * UCHAR FreeMem (PBYTE pMem, ULONG cb) ! 1065: * ! 1066: * Effect: ! 1067: * Frees any memory previously allocated by Allocmem ! 1068: * ! 1069: * Returns value: ! 1070: * NULL ! 1071: \***********************************************************************/ ! 1072: ! 1073: VOID FreeMem(PBYTE pMem, ULONG cb) ! 1074: { ! 1075: DosSubFree((PVOID)pheapSpyHook, (PVOID)pMem, cb); ! 1076: } ! 1077: ! 1078: ! 1079: /*************************** Private Function **************************\ ! 1080: * BOOL EnterSem ! 1081: * ! 1082: * Effect: ! 1083: * Enters the Main spy Mutex semaphore ! 1084: * ! 1085: * Returns value: ! 1086: * BOOL; ! 1087: \***********************************************************************/ ! 1088: ! 1089: BOOL EnterSem(ULONG ulWait) ! 1090: { ! 1091: ULONG rc; ! 1092: HMTX hmtx; ! 1093: ! 1094: if ((rc = DosRequestMutexSem(hmtxSpyHook, ulWait)) == 0) ! 1095: return (TRUE); ! 1096: ! 1097: if (rc != ERROR_INVALID_HANDLE) ! 1098: return (FALSE); ! 1099: #ifdef LATER ! 1100: * We should Close semaphore when we are done??? ! 1101: #endif ! 1102: ! 1103: hmtx = hmtxSpyHook; ! 1104: if (DosOpenMutexSem(NULL, &hmtx) != 0) ! 1105: return (FALSE); ! 1106: ! 1107: DosGetSharedMem(pheapSpyHook, PAG_READ | PAG_WRITE); ! 1108: ! 1109: return (DosRequestMutexSem(hmtxSpyHook, 100L) == 0); ! 1110: ! 1111: } ! 1112: ! 1113: /*************************** Private Function **************************\ ! 1114: * BOOL LeaveSem ! 1115: * ! 1116: * Effect: ! 1117: * Enters the Main spy Mutex semaphore ! 1118: * ! 1119: * Returns value: ! 1120: * BOOL; ! 1121: \***********************************************************************/ ! 1122: ! 1123: BOOL LeaveSem() ! 1124: { ! 1125: return (DosReleaseMutexSem(hmtxSpyHook) == 0); ! 1126: ! 1127: } ! 1128: ! 1129: ! 1130: ! 1131: /*************************** Private Function **************************\ ! 1132: * BOOL SignalEvent ! 1133: * ! 1134: * Effect: ! 1135: * Signal an event to spy to let him know something is available. ! 1136: * ! 1137: * Returns value: ! 1138: * BOOL; ! 1139: \***********************************************************************/ ! 1140: ! 1141: BOOL SignalEvent() ! 1142: { ! 1143: ULONG rc; ! 1144: HEV hev; ! 1145: ! 1146: if ((rc = DosPostEventSem(hevSpyMsg)) == 0) ! 1147: return (TRUE); ! 1148: ! 1149: if (rc != ERROR_INVALID_HANDLE) ! 1150: return (FALSE); ! 1151: #ifdef LATER ! 1152: * We should Close semaphore when we are done??? ! 1153: #endif ! 1154: ! 1155: hev = hevSpyMsg; ! 1156: if (DosOpenEventSem(NULL, &hev) != 0) ! 1157: return (FALSE); ! 1158: ! 1159: return (DosPostEventSem(hevSpyMsg) == 0); ! 1160: ! 1161: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.