Annotation of pmsdk/samples/spy/spyhook.c, revision 1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.