source: trunk/synergy/birdhacks/spy1hk.c@ 3003

Last change on this file since 3003 was 2766, checked in by bird, 19 years ago

a simple spy.

File size: 6.3 KB
Line 
1/* $Id: $ */
2/** @file
3 *
4 * spy1 - Hook DLL.
5 *
6 * Copyright (c) 2006 knut st. osmundsen <bird@anduin.net>
7 *
8 * GPL
9 *
10 */
11
12/*******************************************************************************
13* Header Files *
14*******************************************************************************/
15#define INCL_PM
16#define INCL_BASE
17#define INCL_ERRORS
18#include <os2.h>
19#include "spy1.h"
20
21
22/*******************************************************************************
23* Global Variables *
24*******************************************************************************/
25/** This dll. */
26HMODULE g_hmod = NULLHANDLE;
27/** Consumer. */
28HEV g_hevConsumer = NULLHANDLE;
29
30/** The event 'buffer'.
31 * This is worked with two indexes, one for the producer (the hooks) and one
32 * for the consumer (GetEvent).
33 * When g_iConsumer equals g_iProducer, there are no events in the buffer. */
34SPY1EVENT volatile g_aEvents[1024];
35/** The consumer index. */
36unsigned volatile g_iConsumer;
37/** The producer index. */
38unsigned volatile g_iProducer;
39
40
41/**
42 * The DLL InitTerm function.
43 */
44ULONG EXPENTRY _DLL_InitTerm(HMODULE hmod, ULONG ulReason)
45{
46 HEV hev = g_hevConsumer;
47 switch (ulReason) {
48 case 0:
49 if (hev != NULLHANDLE) {
50 /* instance init */
51 DosOpenEventSem(NULL, &hev);
52 if (g_hmod != hmod) {
53 g_hmod = hmod;
54 }
55 } else {
56 /* global init - can serialize this 100% if it becomes a problem. */
57 if (DosCreateEventSem(NULL, &hev, DC_SEM_SHARED, FALSE) != NO_ERROR) {
58 DosBeep(110, 200);
59 return FALSE;
60 }
61 g_hevConsumer = hev;
62 g_hmod = hmod;
63 g_iConsumer = 0;
64 g_iProducer = 0;
65 }
66 break;
67 case 1:
68 if (hev != NULLHANDLE) {
69 DosCloseEventSem(hev);
70 }
71 break;
72 default:
73 return FALSE;
74 }
75 return TRUE;
76}
77
78
79/**
80 * Sets the hooks.
81 *
82 * @returns PM error on failure. NO_ERROR on success.
83 * @param hab The anchor block of the current thread.
84 */
85int EXPENTRY SetHooks(HAB hab)
86{
87 int rc;
88 if (WinSetHook(hab, NULLHANDLE, HK_INPUT, (PFN)InputHook, g_hmod)) {
89 if (WinSetHook(hab, NULLHANDLE, HK_JOURNALRECORD, (PFN)JournalRecordHook, g_hmod)) {
90 return NO_ERROR;
91 }
92
93 /* bail out */
94 rc = WinGetLastError(hab);
95 WinReleaseHook(hab, NULLHANDLE, HK_INPUT, (PFN)InputHook, g_hmod);
96 } else {
97 rc = WinGetLastError(hab);
98 }
99 return rc;
100}
101
102
103/**
104 * Releases the hooks.
105 *
106 * @returns PM error on failure. NO_ERROR on success.
107 * @param hab The anchor block of the current thread.
108 */
109int EXPENTRY ReleaseHooks(HAB hab)
110{
111 int rc = NO_ERROR;
112 if (!WinReleaseHook(hab, NULLHANDLE, HK_INPUT, (PFN)InputHook, g_hmod)) {
113 rc = WinGetLastError(hab);
114 }
115 if (!WinReleaseHook(hab, NULLHANDLE, HK_JOURNALRECORD, (PFN)JournalRecordHook, g_hmod)) {
116 rc = WinGetLastError(hab);
117 }
118 return rc;
119}
120
121
122/**
123 * Gets a message.
124 *
125 * @returns DosWaitEventSem return code.
126 * @param pEvent Where to store the event.
127 * @param ulTimeout How many milliseconds to wait.
128 */
129int EXPENTRY GetEvent(PSPY1EVENT pEvent, ULONG ulTimeout)
130{
131 /*
132 * Wait for an event to become ready.
133 */
134 unsigned iCur = g_iConsumer;
135 if (iCur == g_iProducer) {
136 do {
137 ULONG cPosts;
138 APIRET rc = DosResetEventSem(g_hevConsumer, &cPosts);
139 if (rc != NO_ERROR && rc != ERROR_ALREADY_RESET) {
140 return rc;
141 }
142 if (iCur != g_iProducer) {
143 break;
144 }
145 rc = DosWaitEventSem(g_hevConsumer, ulTimeout);
146 if (rc) {
147 return rc;
148 }
149 iCur = g_iConsumer;
150 } while (iCur == g_iProducer);
151 }
152
153 /*
154 * Reap the event.
155 */
156 *pEvent = g_aEvents[iCur];
157 const unsigned iNext = (iCur + 1) % (sizeof(g_aEvents) / sizeof(g_aEvents[0]));
158 if (g_iConsumer == iCur) {
159 g_iConsumer = iNext;
160 }
161 return NO_ERROR;
162}
163
164
165/**
166 * Record a message.
167 */
168void RecordMsg(ULONG ulHook, const QMSG *pQmsg, BOOL fRemoved)
169{
170 const unsigned iCur = g_iProducer;
171 const unsigned iNext = (iCur + 1) % (sizeof(g_aEvents) / sizeof(g_aEvents[0]));
172 if (iNext != g_iConsumer) {
173 PTIB pTib;
174 PPIB pPib;
175
176 /* fill in the message data. */
177 g_aEvents[iCur].enmType = fRemoved ? SPY1EVENTTYPE_MSG_REMOVED : SPY1EVENTTYPE_MSG_PEEK;
178 DosGetInfoBlocks(&pTib, &pPib);
179 g_aEvents[iCur].pid = pPib->pib_ulpid;
180 g_aEvents[iCur].tid = pTib->tib_ptib2->tib2_ultid;
181 g_aEvents[iCur].ulHook = ulHook;
182 g_aEvents[iCur].u.Msg = *pQmsg;
183
184 /* commit the message. */
185 if (iCur == g_iProducer) {
186 g_iProducer = iNext;///@todo atomic compare and exchange!
187 DosPostEventSem(g_hevConsumer);
188 }
189 } else {
190 /* the buffer is full */
191 DosPostEventSem(g_hevConsumer);
192 DosSleep(0);
193 }
194}
195
196
197/**
198 * The input hook procedure (any context).
199 *
200 * @returns Processed indicator; TRUE if processed and should be discarded, FALSE if should be passed on.
201 *
202 * @param hab The anchor block of the current thread.
203 * @param pQmsg The message structure containing the message we're called for.
204 * @param fs The removal options (PM_REMOVE / PM_NOREMOVE).
205 */
206BOOL EXPENTRY InputHook(HAB hab, PQMSG pQmsg, ULONG fs)
207{
208 //if (fs == PM_REMOVE) {
209 RecordMsg(HK_INPUT, pQmsg, fs == PM_REMOVE);
210 //}
211 return FALSE;
212}
213
214
215/**
216 * The journal record hook procedure (any context).
217 *
218 * @param hab The anchor block of the current thread.
219 * @param pQmsg The message structure containing the message we're called for.
220 */
221VOID EXPENTRY JournalRecordHook(HAB hab, PQMSG pQmsg)
222{
223 RecordMsg(HK_JOURNALRECORD, pQmsg, TRUE);
224}
225
Note: See TracBrowser for help on using the repository browser.