|
|
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.