|
|
1.1 ! root 1: /***********************************************************************\ ! 2: * spyhook.C - Spy Global input hook interface library. ! 3: * ! 4: * Purpose: This dynlink is needed because global input hooks must ! 5: * reside in a DLL. ! 6: * ! 7: * Created by Microsoft Corp. 1987 ! 8: * ! 9: \***********************************************************************/ ! 10: #define INCL_PM ! 11: #include <os2.h> ! 12: #include "spyhook.h" ! 13: ! 14: ! 15: ULONG spyhookSem = 0L; /* global semaphore for this module */ ! 16: HMODULE hmodSpy; /* dynlink module handle */ ! 17: SHORT SpybHooks; /* Which Hooks do we use */ ! 18: ! 19: HAB habOwner = (HAB)0; /* Hook owner's anchor block */ ! 20: HMQ hmqOwner = (HMQ)0; /* Hook owner's message queue */ ! 21: BOOL fRecording = FALSE; /* Are we recording now? */ ! 22: ! 23: /* Define array of window handles that we are going to process */ ! 24: BOOL fProcessAllFrames = FALSE; /* Are we processing all frame messages */ ! 25: BOOL fProcessAllWindows = FALSE; /* Are we processing all windows */ ! 26: HWND rghwndSpy[MAXHWNDS]; ! 27: int chwndSpy = 0; /* Max windows to spy */ ! 28: ! 29: /* Define message filter array */ ! 30: UCHAR rgMessageFilter[MAXMSGFILTERBYTES] = ""; ! 31: BOOL FMsgInMsgList(USHORT); /* Is message in message list */ ! 32: UCHAR rgBitMasks[8] = {0x01, 0x02, 0x04, 0x08, ! 33: 0x10, 0x20, 0x40, 0x80 }; ! 34: ! 35: ! 36: /* Define an array of messages to pass to whomever calls us */ ! 37: ULONG spyMsgSem = 0L; /* global semaphore for this module */ ! 38: QMSG rgqmsgSpy[MAXMSGCNT]; /* Array of messages to process */ ! 39: SHORT cmsgSpy = 0; /* Count of messages yet to be read */ ! 40: SHORT imsgWrite = 0; /* Index to message to write out */ ! 41: SHORT imsgRead = 0; /* Index to message to read */ ! 42: ! 43: ! 44: ! 45: ! 46: ! 47: /***************************** Exported Function ***********************\ ! 48: * BOOL FAR PASCAL SpyInputHook( hab, lpqmsg ) ! 49: * HAB hab; ! 50: * PQMSG lpqmsg; ! 51: * ! 52: * Effect: This is the global input hook procedure. Note that hook ! 53: * procedures can be chained, so we always return FALSE to pass the ! 54: * message to the next guy in chain. ! 55: * ! 56: * Return value: FALSE to pass message to next hook procedure. ! 57: \***********************************************************************/ ! 58: BOOL FAR PASCAL SpyInputHook( hab, lpqmsg ) ! 59: HAB hab; ! 60: PQMSG lpqmsg; ! 61: { ! 62: /* ! 63: * First check to see if we are processing any hook messages ! 64: */ ! 65: if (!fRecording || (cmsgSpy >= MAXMSGCNT)) ! 66: return (FALSE); /* No let the next one have it now */ ! 67: ! 68: if ((chwndSpy == 0) && !fProcessAllWindows && !fProcessAllFrames) ! 69: return (FALSE); ! 70: ! 71: /* ! 72: * See if we have any messages to process - Recheck to make sure we ! 73: * Dont overwrite our queue. ! 74: */ ! 75: if (DosSemRequest((HSEM)(PULONG)&spyhookSem, 100L) != 0) ! 76: return (FALSE); ! 77: if (cmsgSpy < MAXMSGCNT) { ! 78: if (SpyFWindowInList(lpqmsg->hwnd) && FMsgInMsgList(lpqmsg->msg)) { ! 79: rgqmsgSpy[imsgWrite++] = *lpqmsg; /* Save the message */ ! 80: if (imsgWrite == MAXMSGCNT) ! 81: imsgWrite = 0; /* Wrap around */ ! 82: cmsgSpy++; ! 83: DosSemClear((HSEM)(PULONG)&spyMsgSem); ! 84: } ! 85: } ! 86: ! 87: DosSemClear( (HSEM)(PULONG)&spyhookSem ); ! 88: return FALSE; /* Let system take normal action. */ ! 89: } ! 90: ! 91: ! 92: /***************************** Exported Function ***********************\ ! 93: * BOOL FAR PASCAL SpySendMsgHook( hab, lpsmh, fInterTask) ! 94: * HAB hab; ! 95: * PQMSG lpqmsg; ! 96: * ! 97: * Effect: This is the global input hook procedure. Note that hook ! 98: * procedures can be chained, so we always return FALSE to pass the ! 99: * message to the next guy in chain. ! 100: * ! 101: * Return value: FALSE to pass message to next hook procedure. ! 102: \***********************************************************************/ ! 103: BOOL FAR PASCAL SpySendMsgHook( hab, lpsmh, fInterTask ) ! 104: HAB hab; ! 105: PSMHSTRUCT lpsmh; ! 106: BOOL fInterTask; ! 107: { ! 108: /* ! 109: * First check to see if we are processing any hook messages ! 110: */ ! 111: if (!fRecording || (cmsgSpy >= MAXMSGCNT)) ! 112: return (FALSE); /* No let the next one have it now */ ! 113: ! 114: if ((chwndSpy == 0) && !fProcessAllWindows && !fProcessAllFrames) ! 115: return (FALSE); ! 116: /* ! 117: * See if we have any messages to process ! 118: */ ! 119: if (DosSemRequest((HSEM)(PULONG)&spyhookSem, 100L) != 0) ! 120: return (FALSE); ! 121: /* Make sure no one got in by mistake */ ! 122: if (cmsgSpy < MAXMSGCNT) { ! 123: if (SpyFWindowInList(lpsmh->hwnd) && FMsgInMsgList(lpsmh->msg)) { ! 124: /* ! 125: * Store out message, must move pieces seperatly ! 126: */ ! 127: rgqmsgSpy[imsgWrite].hwnd = lpsmh->hwnd; ! 128: rgqmsgSpy[imsgWrite].msg = lpsmh->msg; ! 129: rgqmsgSpy[imsgWrite].mp1 = lpsmh->mp1; ! 130: rgqmsgSpy[imsgWrite].mp2 = lpsmh->mp2; ! 131: rgqmsgSpy[imsgWrite].time = (ULONG)-1; ! 132: rgqmsgSpy[imsgWrite].ptl.x = (LONG)fInterTask; ! 133: rgqmsgSpy[imsgWrite].ptl.y = 0; ! 134: ! 135: imsgWrite++; ! 136: if (imsgWrite == MAXMSGCNT) ! 137: imsgWrite = 0; /* Wrap around */ ! 138: cmsgSpy++; ! 139: DosSemClear((HSEM)(PULONG)&spyMsgSem); ! 140: } ! 141: } ! 142: ! 143: DosSemClear( (HSEM)(PULONG)&spyhookSem ); ! 144: return FALSE; /* Let system take normal action. */ ! 145: } ! 146: ! 147: ! 148: /*************************** Public Function ***************************\ ! 149: * BOOL FAR PASCAL SpyInstallHook( hab, hmq, fSendMessage, bHooks) ! 150: * ! 151: * Effect: This routine installs a system-wide HK_INPUT hook. The hab ! 152: * hmq are remembered for message posting. Note that we only allow ! 153: * one input hook to be installed through this routine, but other ! 154: * apps may call WinSetHook directly. ! 155: * ! 156: * Returns value: TRUE if hook installed successfully, FALSE otherwise. ! 157: \***********************************************************************/ ! 158: BOOL FAR PASCAL SpyInstallHook( hab, hmq, bHooks ) ! 159: HAB hab; ! 160: HMQ hmq; ! 161: USHORT bHooks; ! 162: { ! 163: BOOL fRet; ! 164: ! 165: DosSemRequest( (HSEM)(PULONG)&spyhookSem, -1L); ! 166: ! 167: /* ! 168: * Look at hook index if == HK_INPUT Install a system-wide input hook. ! 169: * else set system wide SENDMSG hook ! 170: */ ! 171: SpybHooks = bHooks; ! 172: if (SpybHooks & SPYH_INPUT) ! 173: fRet = WinSetHook( hab, (HMQ)0, HK_INPUT, (PFN)SpyInputHook, ! 174: hmodSpy ); ! 175: ! 176: if (SpybHooks & SPYH_SENDMSG) ! 177: fRet = WinSetHook( hab, (HMQ)0, HK_SENDMSG, (PFN)SpySendMsgHook, ! 178: hmodSpy ); ! 179: if (fRet) { ! 180: habOwner = hab; ! 181: hmqOwner = hmq; ! 182: } ! 183: ! 184: DosSemSet((HSEM)(PULONG)&spyMsgSem); /* Init, no messages avail */ ! 185: DosSemClear( (HSEM)(PULONG)&spyhookSem ); ! 186: ! 187: return fRet; ! 188: } ! 189: ! 190: ! 191: ! 192: /*************************** Public Function ***************************\ ! 193: * BOOL FAR PASCAL SpySetWindowList( chwnd, rghwnd) ! 194: * ! 195: * Effect: This routine sets the list of window that we are interested ! 196: * in watching the messages for. ! 197: * ! 198: * Returns value: TRUE ! 199: \***********************************************************************/ ! 200: BOOL FAR PASCAL SpySetWindowList( chwnd, rghwnd ) ! 201: SHORT chwnd; ! 202: HWND FAR *rghwnd; ! 203: { ! 204: SHORT i; ! 205: ! 206: DosSemRequest( (HSEM)(PULONG)&spyhookSem, -1L); ! 207: ! 208: chwndSpy = chwnd; ! 209: ! 210: for (i=0; i < chwnd; i++) { ! 211: rghwndSpy[i] = *rghwnd++; ! 212: } ! 213: ! 214: DosSemClear( (HSEM)(PULONG)&spyhookSem ); ! 215: ! 216: return(TRUE); ! 217: } ! 218: ! 219: ! 220: /*************************** Public Function ***************************\ ! 221: * BOOL FAR PASCAL SpyGetWindowList( chwnd, rghwnd) ! 222: * ! 223: * Effect: This routine sets the list of window that we are interested ! 224: * in watching the messages for. ! 225: * ! 226: * Returns value: TRUE ! 227: \***********************************************************************/ ! 228: SHORT FAR PASCAL SpyGetWindowList( chwnd, rghwnd ) ! 229: SHORT chwnd; ! 230: HWND FAR *rghwnd; ! 231: { ! 232: SHORT i; ! 233: ! 234: DosSemRequest( (HSEM)(PULONG)&spyhookSem, -1L); ! 235: ! 236: if (chwnd > chwndSpy) ! 237: chwnd = chwndSpy; ! 238: ! 239: for (i=0; i < chwnd; i++) { ! 240: *rghwnd++ = rghwndSpy[i]; ! 241: } ! 242: ! 243: DosSemClear( (HSEM)(PULONG)&spyhookSem ); ! 244: ! 245: return(chwnd); ! 246: } ! 247: ! 248: ! 249: /*************************** Public Function ***************************\ ! 250: * BOOL FAR PASCAL SpySetMessageList( chwnd, rghwnd) ! 251: * ! 252: * Effect: This routine sets the list of window that we are interested ! 253: * in watching the messages for. ! 254: * ! 255: * Returns value: TRUE ! 256: \***********************************************************************/ ! 257: BOOL FAR PASCAL SpySetMessageList(prgNewMsgFilter) ! 258: UCHAR FAR *prgNewMsgFilter; ! 259: { ! 260: SHORT i; ! 261: unsigned char *prgb; ! 262: ! 263: DosSemRequest( (HSEM)(PULONG)&spyhookSem, -1L); ! 264: ! 265: prgb = rgMessageFilter; ! 266: ! 267: for (i=0; i < MAXMSGFILTERBYTES; i++) { ! 268: *prgb++ = *prgNewMsgFilter++; ! 269: } ! 270: ! 271: DosSemClear( (HSEM)(PULONG)&spyhookSem ); ! 272: ! 273: return(TRUE); ! 274: } ! 275: ! 276: ! 277: /*************************** Public Function ***************************\ ! 278: * BOOL FAR PASCAL SpyFWindowInList (hwnd) ! 279: * ! 280: * Effect: This function checks our current list of windows, and returns ! 281: * TRUE if the window is in the list, else returns FALSE. ! 282: * Returns value: TRUE if window is in list. Also if We are in the special ! 283: * state we will pass through all frame windows. ! 284: \***********************************************************************/ ! 285: BOOL FAR PASCAL SpyFWindowInList (hwnd) ! 286: register HWND hwnd; ! 287: { ! 288: register int i; ! 289: char szClassName[10]; /* Class name of window */ ! 290: CLASSINFO classinfo; /* Information about class */ ! 291: ! 292: if (fProcessAllWindows) ! 293: return (TRUE); /* All windows pass through */ ! 294: ! 295: for (i=0; i< chwndSpy; i++) { ! 296: if (hwnd == rghwndSpy[i]) ! 297: return (TRUE); ! 298: } ! 299: ! 300: if (fProcessAllFrames) { ! 301: /* See if frame class */ ! 302: if (hwnd == NULL) ! 303: return (TRUE); /* pass queue messages through */ ! 304: WinQueryClassName(hwnd, sizeof(szClassName), ! 305: (PSZ)szClassName); ! 306: WinQueryClassInfo((HAB)NULL, (PSZ)szClassName, ! 307: &classinfo); ! 308: if (classinfo.flClassStyle & CS_FRAME) ! 309: return (TRUE); ! 310: } ! 311: ! 312: return (FALSE); ! 313: } ! 314: ! 315: ! 316: /*************************** Public Function ***************************\ ! 317: * BOOL FAR PASCAL SpyReleaseHook(fZeroQueue) ! 318: * ! 319: * Effect: This routine releases the input hook, if it is installed. ! 320: * ! 321: * Returns value: TRUE if hook is released, FALSE otherwise. ! 322: \***********************************************************************/ ! 323: BOOL FAR PASCAL SpyReleaseHook(fZeroQueue) ! 324: BOOL fZeroQueue; ! 325: { ! 326: BOOL fRet; ! 327: ! 328: DosSemRequest ( (HSEM)(PULONG)&spyhookSem, -1L ); ! 329: ! 330: if ( habOwner ) { ! 331: if (SpybHooks & SPYH_INPUT) ! 332: fRet = WinReleaseHook( habOwner, (HMQ)0, HK_INPUT, ! 333: (PFN)SpyInputHook, hmodSpy ); ! 334: ! 335: if (SpybHooks & SPYH_SENDMSG) ! 336: fRet = WinReleaseHook( habOwner, (HMQ)0, HK_SENDMSG, ! 337: (PFN)SpySendMsgHook, hmodSpy ); ! 338: if ( fRet ) { ! 339: habOwner = (HAB)0; ! 340: hmqOwner = (HMQ)0; ! 341: } ! 342: } ! 343: ! 344: /* ! 345: * When the hook is freed, we want to clear message count out, ! 346: * make sure any process waiting will abort ! 347: * Only do this if the Zeroqueu flag was passed ! 348: */ ! 349: if (fZeroQueue) { ! 350: cmsgSpy = 0; ! 351: imsgWrite = 0; ! 352: imsgRead = 0; ! 353: chwndSpy = 0; /* Max windows to spy */ ! 354: fRecording = FALSE; /* Set recording to off */ ! 355: DosSemClear((HSEM)(PULONG)&spyMsgSem); /* Free any process */ ! 356: } ! 357: DosSemClear((HSEM)(PULONG)&spyhookSem); ! 358: ! 359: return fRet; ! 360: } ! 361: ! 362: ! 363: /*************************** Public Function ***************************\ ! 364: * BOOL FAR PASCAL SpyHookOnOrOff( fOn) ! 365: * ! 366: * Effect: This routine allows the application to turn the hook ! 367: * processing on or off. ! 368: * ! 369: * Returns value: ! 370: \***********************************************************************/ ! 371: BOOL FAR PASCAL SpyHookOnOrOff(fOn) ! 372: BOOL fOn; ! 373: { ! 374: DosSemRequest ( (HSEM)(PULONG)&spyhookSem, -1L); ! 375: ! 376: fRecording = fOn; ! 377: ! 378: DosSemClear( (HSEM)(PULONG)&spyhookSem ); ! 379: return (TRUE); ! 380: } ! 381: ! 382: ! 383: ! 384: /*************************** Public Function ***************************\ ! 385: * BOOL FAR PASCAL SpySetAllFrameOpt(fAllFrames) ! 386: * ! 387: * Effect: Special state if TRUE will cause the window filter to pass ! 388: * all frame windows through. This is usefull when debuging ! 389: * interactions between frame windows, when the windows are ! 390: * net yet created. ! 391: * ! 392: * Returns value: ! 393: \***********************************************************************/ ! 394: BOOL FAR PASCAL SpySetAllFrameOpt(fAllFrames) ! 395: BOOL fAllFrames; ! 396: { ! 397: fProcessAllFrames = fAllFrames; ! 398: return (TRUE); ! 399: } ! 400: /*************************** Public Function ***************************\ ! 401: * BOOL FAR PASCAL SpySetAllWindowOpt(fAllWindows) ! 402: * ! 403: * Effect: Special state if TRUE will cause the window filter to pass ! 404: * all windows through. This is usefull when debuging ! 405: * interactions between all of the windows ! 406: * ! 407: * Returns value: ! 408: \***********************************************************************/ ! 409: BOOL FAR PASCAL SpySetAllWindowOpt(fAllWindows) ! 410: BOOL fAllWindows; ! 411: { ! 412: fProcessAllWindows = fAllWindows; ! 413: return (TRUE); ! 414: } ! 415: ! 416: /*************************** Public Function **************************\ ! 417: * SpyGetNextMessage (lpqmsg, lTimeOut) ! 418: * ! 419: * Effect: ! 420: * Get the next message from the list - if timeout != 0 an message ! 421: * processing threads, you may have problems, - If lpqmsg==NULL, this ! 422: * function acts like a query or wait function. ! 423: * ! 424: * Returns value: ! 425: \***********************************************************************/ ! 426: BOOL FAR PASCAL SpyGetNextMessage(lpqmsg, lTimeOut) ! 427: PQMSG lpqmsg; ! 428: LONG lTimeOut; ! 429: { ! 430: /* Quick escape hatch */ ! 431: if ((lTimeOut == 0) && (cmsgSpy == 0)) ! 432: return (FALSE); /* Dont Wait */ ! 433: ! 434: /* ! 435: * Now lets possibly wait for a message ! 436: */ ! 437: if (cmsgSpy == 0) { ! 438: if (DosSemWait((HSEM)(PULONG)&spyMsgSem, lTimeOut) != 0) ! 439: return (FALSE); /* No messages after timeout */ ! 440: if (cmsgSpy == 0) ! 441: return (FALSE); /* Still no messages, return condition */ ! 442: } ! 443: ! 444: /* ! 445: * If the lpqmsg is NULL, the user is simply asking if there is ! 446: * a message and/or waiting for the message, so dont extract ! 447: * the message, but simply return the status. ! 448: */ ! 449: if (lpqmsg != NULL) { ! 450: if (DosSemRequest((HSEM)(PULONG)&spyhookSem, lTimeOut) == 0) { ! 451: *lpqmsg = rgqmsgSpy[imsgRead++]; /* Extract the message */ ! 452: if (imsgRead == MAXMSGCNT) ! 453: imsgRead = 0; /* Wrap around */ ! 454: ! 455: /* ! 456: * Decrement count of messages, if we go to zero, set ! 457: * the semaphore, so that the next read will suspend until ! 458: * the next message ! 459: */ ! 460: cmsgSpy--; ! 461: if (cmsgSpy == 0) ! 462: DosSemSet((HSEM)(PULONG)&spyMsgSem); ! 463: ! 464: DosSemClear( (HSEM)(PULONG)&spyhookSem ); ! 465: } ! 466: } ! 467: ! 468: return (TRUE); ! 469: } ! 470: ! 471: ! 472: ! 473: ! 474: /*************************** Private Function **************************\ ! 475: * VOID PASCAL Init( hmod ) ! 476: * ! 477: * Effect: ! 478: * ! 479: * ! 480: * Returns value: ! 481: \***********************************************************************/ ! 482: VOID PASCAL Init( hmod ) ! 483: HMODULE hmod; ! 484: { ! 485: register INT i; ! 486: ! 487: /* Save the module handle. */ ! 488: hmodSpy = hmod; ! 489: } ! 490: ! 491: ! 492: /*************************** Private Function **************************\ ! 493: * Bool FMsgInMsgList (USHORT msg) ! 494: * ! 495: * Effect: ! 496: * Should the message be processed. If the message is out of range, ! 497: * or bit is set in message bitmask return TRUE ! 498: * ! 499: * Returns value: ! 500: * BOOL ! 501: \***********************************************************************/ ! 502: BOOL FMsgInMsgList(msg) ! 503: USHORT msg; ! 504: { ! 505: if (msg > MAXMSGFILTER) ! 506: return (TRUE); ! 507: ! 508: if (rgMessageFilter[msg >> 3] & rgBitMasks[msg & 0x07]) ! 509: return (TRUE); ! 510: return (FALSE); ! 511: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.