~ubuntu-branches/ubuntu/feisty/apache2/feisty

« back to all changes in this revision

Viewing changes to server/mpm/winnt/Win9xConHook.c

  • Committer: Bazaar Package Importer
  • Author(s): Andreas Barth
  • Date: 2006-12-09 21:05:45 UTC
  • mfrom: (0.6.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20061209210545-h70s0xaqc2v8vqr2
Tags: 2.2.3-3.2
* Non-maintainer upload.
* 043_ajp_connection_reuse: Patch from upstream Bugzilla, fixing a critical
  issue with regard to connection reuse in mod_proxy_ajp.
  Closes: #396265

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Licensed to the Apache Software Foundation (ASF) under one or more
 
2
 * contributor license agreements.  See the NOTICE file distributed with
 
3
 * this work for additional information regarding copyright ownership.
 
4
 * The ASF licenses this file to You under the Apache License, Version 2.0
 
5
 * (the "License"); you may not use this file except in compliance with
 
6
 * the License.  You may obtain a copy of the License at
 
7
 *
 
8
 *     http://www.apache.org/licenses/LICENSE-2.0
 
9
 *
 
10
 * Unless required by applicable law or agreed to in writing, software
 
11
 * distributed under the License is distributed on an "AS IS" BASIS,
 
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
13
 * See the License for the specific language governing permissions and
 
14
 * limitations under the License.
 
15
 */
 
16
 
 
17
#ifdef WIN32
 
18
 
 
19
/*
 
20
 * Win9xConHook.dll - a hook proc to clean up Win95/98 console behavior.
 
21
 *
 
22
 * It is well(?) documented by Microsoft that the Win9x HandlerRoutine
 
23
 * hooked by the SetConsoleCtrlHandler never receives the CTRL_CLOSE_EVENT,
 
24
 * CTRL_LOGOFF_EVENT or CTRL_SHUTDOWN_EVENT signals.
 
25
 *
 
26
 * It is possible to have a second window to monitor the WM_ENDSESSION
 
27
 * message, but the close button still fails..
 
28
 *
 
29
 * There is a 16bit polling method for the close window option, but this
 
30
 * is CPU intensive and requires thunking.
 
31
 *
 
32
 * Attempts to subclass the 'tty' console fail, since that message thread
 
33
 * is actually owned by the 16 bit winoldap.mod process, although the
 
34
 * window reports it is owned by the process/thread of the console app.
 
35
 *
 
36
 * Win9xConHook is thunks the WM_CLOSE and WM_ENDSESSION messages,
 
37
 * first through a window hook procedure in the winoldap context, into
 
38
 * a subclass WndProc, and on to a second hidden monitor window in the
 
39
 * console application's context that dispatches them to the console app's
 
40
 * registered HandlerRoutine.
 
41
 */
 
42
 
 
43
/* This debugging define turns on output to COM1, although you better init
 
44
 * the port first (even using hyperterm).  It's the only way to catch the
 
45
 * goings on within system logoff/shutdown.
 
46
 * #define DBG 1
 
47
 */
 
48
 
 
49
#include <windows.h>
 
50
 
 
51
/* Variables used within any process context:
 
52
 *  hookwndmsg is a shared message to send Win9xConHook signals
 
53
 *  origwndprop is a wndprop atom to store the orig wndproc of the tty
 
54
 *  hookwndprop is a wndprop atom to store the hwnd of the hidden child
 
55
 *  is_service reminds us to unmark this process on the way out
 
56
 */
 
57
static UINT hookwndmsg = 0;
 
58
static LPCTSTR origwndprop;
 
59
static LPCTSTR hookwndprop;
 
60
static BOOL is_service = 0;
 
61
//static HMODULE hmodThis = NULL;
 
62
 
 
63
/* Variables used within the tty processes' context:
 
64
 *  is_tty flags this process;  -1 == unknown, 1 == if tty, 0 == if not
 
65
 *  hw_tty is the handle of the top level tty in this process context
 
66
 *  is_subclassed is toggled to assure DllMain removes the subclass on unload
 
67
 *  hmodLock is there to try and prevent this dll from being unloaded if the
 
68
 *           hook is removed while we are subclassed
 
69
 */
 
70
static int is_tty = -1;
 
71
static HWND hwtty = NULL;
 
72
static BOOL is_subclassed = 0;
 
73
 
 
74
// This simply causes a gpfault the moment it tries to FreeLibrary within
 
75
// the subclass procedure ... not good.
 
76
//static HMODULE hmodLock = NULL;
 
77
 
 
78
/* Variables used within the service or console app's context:
 
79
 *  hmodHook is the instance handle of this module for registering the hooks
 
80
 *  hhkGetMessage is the hook handle for catching Posted messages
 
81
 *  hhkGetMessage is the hook handle for catching Sent messages
 
82
 *  monitor_hwnd is the invisible window that handles our tty messages
 
83
 *  the tty_info strucure is used to pass args into the hidden window's thread
 
84
 */
 
85
static HMODULE hmodHook = NULL;
 
86
static HHOOK hhkGetMessage;
 
87
//static HHOOK hhkCallWndProc;
 
88
static HWND monitor_hwnd = NULL;
 
89
 
 
90
typedef struct {
 
91
    PHANDLER_ROUTINE phandler;
 
92
    HINSTANCE instance;
 
93
    HWND parent;
 
94
    INT type;
 
95
    LPCSTR name;
 
96
} tty_info;
 
97
 
 
98
/* These are the GetWindowLong offsets for the hidden window's internal info
 
99
 *  gwltty_phandler is the address of the app's HandlerRoutine
 
100
 *  gwltty_ttywnd is the tty this hidden window will handle messages from
 
101
 */
 
102
#define gwltty_phandler 0
 
103
#define gwltty_ttywnd 4
 
104
 
 
105
/* Forward declaration prototypes for internal functions
 
106
 */
 
107
static BOOL CALLBACK EnumttyWindow(HWND wnd, LPARAM retwnd);
 
108
static LRESULT WINAPI RegisterWindows9xService(BOOL set_service);
 
109
static LRESULT CALLBACK ttyConsoleCtrlWndProc(HWND hwnd, UINT msg,
 
110
                                              WPARAM wParam, LPARAM lParam);
 
111
static DWORD WINAPI ttyConsoleCtrlThread(LPVOID tty);
 
112
static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg,
 
113
                                WPARAM wParam, LPARAM lParam);
 
114
static int HookProc(int hc, HWND *hwnd, UINT *msg,
 
115
                    WPARAM *wParam, LPARAM *lParam);
 
116
#ifdef DBG
 
117
static VOID DbgPrintf(LPTSTR fmt, ...);
 
118
#endif
 
119
 
 
120
 
 
121
/* DllMain is invoked by every process in the entire system that is hooked
 
122
 * by our window hooks, notably the tty processes' context, and by the user
 
123
 * who wants tty messages (the app).  Keep it light and simple.
 
124
 */
 
125
BOOL __declspec(dllexport) APIENTRY DllMain(HINSTANCE hModule, ULONG ulReason,
 
126
                                            LPVOID pctx)
 
127
{
 
128
    if (ulReason == DLL_PROCESS_ATTACH)
 
129
    {
 
130
        //hmodThis = hModule;
 
131
        if (!hookwndmsg) {
 
132
            origwndprop = MAKEINTATOM(GlobalAddAtom("Win9xConHookOrigProc"));
 
133
            hookwndprop = MAKEINTATOM(GlobalAddAtom("Win9xConHookThunkWnd"));
 
134
            hookwndmsg = RegisterWindowMessage("Win9xConHookMsg");
 
135
        }
 
136
#ifdef DBG
 
137
//        DbgPrintf("H ProcessAttach:%8.8x\r\n",
 
138
//                  GetCurrentProcessId());
 
139
#endif
 
140
    }
 
141
    else if ( ulReason == DLL_PROCESS_DETACH )
 
142
    {
 
143
#ifdef DBG
 
144
//        DbgPrintf("H ProcessDetach:%8.8x\r\n", GetCurrentProcessId());
 
145
#endif
 
146
        if (monitor_hwnd)
 
147
            SendMessage(monitor_hwnd, WM_DESTROY, 0, 0);
 
148
        if (is_subclassed)
 
149
            SendMessage(hwtty, hookwndmsg, 0, (LPARAM)hwtty);
 
150
        if (hmodHook)
 
151
        {
 
152
            if (hhkGetMessage) {
 
153
                UnhookWindowsHookEx(hhkGetMessage);
 
154
                hhkGetMessage = NULL;
 
155
            }
 
156
            //if (hhkCallWndProc) {
 
157
            //    UnhookWindowsHookEx(hhkCallWndProc);
 
158
            //    hhkCallWndProc = NULL;
 
159
            //}
 
160
            FreeLibrary(hmodHook);
 
161
            hmodHook = NULL;
 
162
        }
 
163
        if (is_service)
 
164
            RegisterWindows9xService(FALSE);
 
165
        if (hookwndmsg) {
 
166
            GlobalDeleteAtom((ATOM)origwndprop);
 
167
            GlobalDeleteAtom((ATOM)hookwndprop);
 
168
            hookwndmsg = 0;
 
169
        }
 
170
    }
 
171
    return TRUE;
 
172
}
 
173
 
 
174
 
 
175
/*  This group of functions are provided for the service/console app
 
176
 *  to register itself a HandlerRoutine to accept tty or service messages
 
177
 */
 
178
 
 
179
 
 
180
/*  Exported function that creates a Win9x 'service' via a hidden window,
 
181
 *  that notifies the process via the HandlerRoutine messages.
 
182
 */
 
183
BOOL __declspec(dllexport) WINAPI Windows9xServiceCtrlHandler(
 
184
        PHANDLER_ROUTINE phandler,
 
185
        LPCSTR name)
 
186
{
 
187
    /* If we have not yet done so */
 
188
    FreeConsole();
 
189
 
 
190
    if (name)
 
191
    {
 
192
        DWORD tid;
 
193
        HANDLE hThread;
 
194
        /* NOTE: this is static so the module can continue to
 
195
         * access these args while we go on to other things
 
196
         */
 
197
        static tty_info tty;
 
198
        tty.instance = GetModuleHandle(NULL);
 
199
        tty.phandler = phandler;
 
200
        tty.parent = NULL;
 
201
        tty.name = name;
 
202
        tty.type = 2;
 
203
        RegisterWindows9xService(TRUE);
 
204
        hThread = CreateThread(NULL, 0, ttyConsoleCtrlThread,
 
205
                               (LPVOID)&tty, 0, &tid);
 
206
        if (hThread)
 
207
        {
 
208
            CloseHandle(hThread);
 
209
            return TRUE;
 
210
        }
 
211
    }
 
212
    else /* remove */
 
213
    {
 
214
        if (monitor_hwnd)
 
215
            SendMessage(monitor_hwnd, WM_DESTROY, 0, 0);
 
216
        RegisterWindows9xService(FALSE);
 
217
        return TRUE;
 
218
    }
 
219
    return FALSE;
 
220
}
 
221
 
 
222
 
 
223
/*  Exported function that registers a HandlerRoutine to accept missing
 
224
 *  Win9x CTRL_EVENTs from the tty window, as NT does without a hassle.
 
225
 *  If add is 1 or 2, register the handler, if 2 also mark it as a service.
 
226
 *  If add is 0 deregister the handler, and unmark if a service
 
227
 */
 
228
BOOL __declspec(dllexport) WINAPI FixConsoleCtrlHandler(
 
229
        PHANDLER_ROUTINE phandler,
 
230
        INT add)
 
231
{
 
232
    HWND parent;
 
233
 
 
234
    if (add)
 
235
    {
 
236
        HANDLE hThread;
 
237
        DWORD tid;
 
238
        /* NOTE: this is static so the module can continue to
 
239
         * access these args while we go on to other things
 
240
         */
 
241
        static tty_info tty;
 
242
        EnumWindows(EnumttyWindow, (LPARAM)&parent);
 
243
        if (!parent) {
 
244
#ifdef DBG
 
245
            DbgPrintf("A EnumttyWindow failed (%d)\r\n", GetLastError());
 
246
#endif
 
247
            return FALSE;
 
248
        }
 
249
        tty.instance = GetModuleHandle(NULL);
 
250
        tty.phandler = phandler;
 
251
        tty.parent = parent;
 
252
        tty.type = add;
 
253
        if (add == 2) {
 
254
            tty.name = "ttyService";
 
255
            RegisterWindows9xService(TRUE);
 
256
        }
 
257
        else
 
258
            tty.name = "ttyMonitor";
 
259
        hThread = CreateThread(NULL, 0, ttyConsoleCtrlThread,
 
260
                               (LPVOID)&tty, 0, &tid);
 
261
        if (!hThread)
 
262
            return FALSE;
 
263
        CloseHandle(hThread);
 
264
        hmodHook = LoadLibrary("Win9xConHook.dll");
 
265
        if (hmodHook)
 
266
        {
 
267
            hhkGetMessage = SetWindowsHookEx(WH_GETMESSAGE,
 
268
              (HOOKPROC)GetProcAddress(hmodHook, "GetMsgProc"), hmodHook, 0);
 
269
            //hhkCallWndProc = SetWindowsHookEx(WH_CALLWNDPROC,
 
270
            //  (HOOKPROC)GetProcAddress(hmodHook, "CallWndProc"), hmodHook, 0);
 
271
        }
 
272
        return TRUE;
 
273
    }
 
274
    else /* remove */
 
275
    {
 
276
        if (monitor_hwnd) {
 
277
            SendMessage(monitor_hwnd, WM_DESTROY, 0, 0);
 
278
        }
 
279
        if (hmodHook)
 
280
        {
 
281
            if (hhkGetMessage) {
 
282
                UnhookWindowsHookEx(hhkGetMessage);
 
283
                hhkGetMessage = NULL;
 
284
            }
 
285
            //if (hhkCallWndProc) {
 
286
            //    UnhookWindowsHookEx(hhkCallWndProc);
 
287
            //    hhkCallWndProc = NULL;
 
288
            //}
 
289
            FreeLibrary(hmodHook);
 
290
            hmodHook = NULL;
 
291
        }
 
292
        if (is_service)
 
293
            RegisterWindows9xService(FALSE);
 
294
        return TRUE;
 
295
    }
 
296
    return FALSE;
 
297
}
 
298
 
 
299
 
 
300
/*  The following internal helpers are only used within the app's context
 
301
 */
 
302
 
 
303
/* ttyConsoleCreateThread is the process that runs within the user app's
 
304
 * context.  It creates and pumps the messages of a hidden monitor window,
 
305
 * watching for messages from the system, or the associated subclassed tty
 
306
 * window.  Things can happen in our context that can't be done from the
 
307
 * tty's context, and visa versa, so the subclass procedure and this hidden
 
308
 * window work together to make it all happen.
 
309
 */
 
310
static DWORD WINAPI ttyConsoleCtrlThread(LPVOID tty)
 
311
{
 
312
    WNDCLASS wc;
 
313
    MSG msg;
 
314
    wc.style         = CS_GLOBALCLASS;
 
315
    wc.lpfnWndProc   = ttyConsoleCtrlWndProc;
 
316
    wc.cbClsExtra    = 0;
 
317
    wc.cbWndExtra    = 8;
 
318
    wc.hInstance     = NULL;
 
319
    wc.hIcon         = NULL;
 
320
    wc.hCursor       = NULL;
 
321
    wc.hbrBackground = NULL;
 
322
    wc.lpszMenuName  = NULL;
 
323
    if (((tty_info*)tty)->parent)
 
324
        wc.lpszClassName = "ttyConHookChild";
 
325
    else
 
326
        wc.lpszClassName = "ApacheWin95ServiceMonitor";
 
327
 
 
328
    if (!RegisterClass(&wc)) {
 
329
#ifdef DBG
 
330
        DbgPrintf("A proc %8.8x Error creating class %s (%d)\r\n",
 
331
                  GetCurrentProcessId(), wc.lpszClassName, GetLastError());
 
332
#endif
 
333
        return 0;
 
334
    }
 
335
 
 
336
    /* Create an invisible window */
 
337
    monitor_hwnd = CreateWindow(wc.lpszClassName, ((tty_info*)tty)->name,
 
338
                                WS_OVERLAPPED & ~WS_VISIBLE,
 
339
                                CW_USEDEFAULT, CW_USEDEFAULT,
 
340
                                CW_USEDEFAULT, CW_USEDEFAULT,
 
341
                                NULL, NULL,
 
342
                                ((tty_info*)tty)->instance, tty);
 
343
 
 
344
    if (!monitor_hwnd) {
 
345
#ifdef DBG
 
346
        DbgPrintf("A proc %8.8x Error creating window %s %s (%d)\r\n",
 
347
                  GetCurrentProcessId(), wc.lpszClassName,
 
348
                  ((tty_info*)tty)->name, GetLastError());
 
349
#endif
 
350
        return 0;
 
351
    }
 
352
 
 
353
    while (GetMessage(&msg, NULL, 0, 0))
 
354
    {
 
355
        TranslateMessage(&msg);
 
356
        DispatchMessage(&msg);
 
357
    }
 
358
 
 
359
    /* Tag again as deleted, just in case we missed WM_DESTROY */
 
360
    monitor_hwnd = NULL;
 
361
    return 0;
 
362
}
 
363
 
 
364
 
 
365
/* This is the WndProc procedure for our invisible window.
 
366
 * When our subclasssed tty window receives the WM_CLOSE, WM_ENDSESSION,
 
367
 * or WM_QUERYENDSESSION messages, the message is dispatched to our hidden
 
368
 * window (this message process), and we call the installed HandlerRoutine
 
369
 * that was registered by the app.
 
370
 */
 
371
static LRESULT CALLBACK ttyConsoleCtrlWndProc(HWND hwnd, UINT msg,
 
372
                                              WPARAM wParam, LPARAM lParam)
 
373
{
 
374
    if (msg == WM_CREATE)
 
375
    {
 
376
        tty_info *tty = (tty_info*)(((LPCREATESTRUCT)lParam)->lpCreateParams);
 
377
        SetWindowLong(hwnd, gwltty_phandler, (LONG)tty->phandler);
 
378
        SetWindowLong(hwnd, gwltty_ttywnd, (LONG)tty->parent);
 
379
#ifdef DBG
 
380
        DbgPrintf("A proc %8.8x created %8.8x %s for tty wnd %8.8x\r\n",
 
381
                  GetCurrentProcessId(), hwnd,
 
382
                  tty->name, tty->parent);
 
383
#endif
 
384
        if (tty->parent) {
 
385
            SetProp(tty->parent, hookwndprop, hwnd);
 
386
            PostMessage(tty->parent, hookwndmsg,
 
387
                        tty->type, (LPARAM)tty->parent);
 
388
        }
 
389
        return 0;
 
390
    }
 
391
    else if (msg == WM_DESTROY)
 
392
    {
 
393
        HWND parent = (HWND)GetWindowLong(hwnd, gwltty_ttywnd);
 
394
#ifdef DBG
 
395
        DbgPrintf("A proc %8.8x destroyed %8.8x ttyConHookChild\r\n",
 
396
                  GetCurrentProcessId(), hwnd);
 
397
#endif
 
398
        if (parent) {
 
399
            RemoveProp(parent, hookwndprop);
 
400
            SendMessage(parent, hookwndmsg, 0, (LPARAM)parent);
 
401
        }
 
402
        monitor_hwnd = NULL;
 
403
    }
 
404
    else if (msg == WM_CLOSE)
 
405
    {
 
406
        PHANDLER_ROUTINE phandler =
 
407
            (PHANDLER_ROUTINE)GetWindowLong(hwnd, gwltty_phandler);
 
408
        LRESULT rv = phandler(CTRL_CLOSE_EVENT);
 
409
#ifdef DBG
 
410
        DbgPrintf("A proc %8.8x invoked CTRL_CLOSE_EVENT "
 
411
                  "returning %d\r\n",
 
412
                  GetCurrentProcessId(), rv);
 
413
#endif
 
414
        if (rv)
 
415
            return !rv;
 
416
    }
 
417
    else if ((msg == WM_QUERYENDSESSION) || (msg == WM_ENDSESSION))
 
418
    {
 
419
        if (lParam & ENDSESSION_LOGOFF)
 
420
        {
 
421
            PHANDLER_ROUTINE phandler =
 
422
                (PHANDLER_ROUTINE)GetWindowLong(hwnd, gwltty_phandler);
 
423
            LRESULT rv = phandler(CTRL_LOGOFF_EVENT);
 
424
#ifdef DBG
 
425
            DbgPrintf("A proc %8.8x invoked CTRL_LOGOFF_EVENT "
 
426
                      "returning %d\r\n",
 
427
                      GetCurrentProcessId(), rv);
 
428
#endif
 
429
            if (rv)
 
430
                return ((msg == WM_QUERYENDSESSION) ? rv : !rv);
 
431
        }
 
432
        else
 
433
        {
 
434
            PHANDLER_ROUTINE phandler =
 
435
                (PHANDLER_ROUTINE)GetWindowLong(hwnd, gwltty_phandler);
 
436
            LRESULT rv = phandler(CTRL_SHUTDOWN_EVENT);
 
437
#ifdef DBG
 
438
            DbgPrintf("A proc %8.8x invoked CTRL_SHUTDOWN_EVENT "
 
439
                      "returning %d\r\n", GetCurrentProcessId(), rv);
 
440
#endif
 
441
            if (rv)
 
442
                return ((msg == WM_QUERYENDSESSION) ? rv : !rv);
 
443
        }
 
444
    }
 
445
    return (DefWindowProc(hwnd, msg, wParam, lParam));
 
446
}
 
447
 
 
448
 
 
449
/*  The following internal helpers are invoked by the hooked tty and our app
 
450
 */
 
451
 
 
452
 
 
453
/*  Register or deregister the current process as a Windows9x style service.
 
454
 *  Experience shows this call is ignored across processes, so the second
 
455
 *  arg to RegisterServiceProcess (process group id) is effectively useless.
 
456
 */
 
457
static LRESULT WINAPI RegisterWindows9xService(BOOL set_service)
 
458
{
 
459
    static HINSTANCE hkernel;
 
460
    static DWORD (WINAPI *register_service_process)(DWORD, DWORD) = NULL;
 
461
    BOOL rv;
 
462
 
 
463
    if (set_service == is_service)
 
464
        return 1;
 
465
 
 
466
#ifdef DBG
 
467
    DbgPrintf("R %s proc %8.8x as a service\r\n",
 
468
              set_service ? "installing" : "removing",
 
469
              GetCurrentProcessId());
 
470
#endif
 
471
 
 
472
    if (!register_service_process)
 
473
    {
 
474
        /* Obtain a handle to the kernel library */
 
475
        hkernel = LoadLibrary("KERNEL32.DLL");
 
476
        if (!hkernel)
 
477
            return 0;
 
478
 
 
479
        /* Find the RegisterServiceProcess function */
 
480
        register_service_process = (DWORD (WINAPI *)(DWORD, DWORD))
 
481
                         GetProcAddress(hkernel, "RegisterServiceProcess");
 
482
        if (register_service_process == NULL) {
 
483
            FreeLibrary(hkernel);
 
484
            return 0;
 
485
        }
 
486
    }
 
487
 
 
488
    /* Register this process as a service */
 
489
    rv = register_service_process(0, set_service != FALSE);
 
490
    if (rv)
 
491
        is_service = set_service;
 
492
 
 
493
    if (!is_service)
 
494
    {
 
495
        /* Unload the kernel library */
 
496
        FreeLibrary(hkernel);
 
497
        register_service_process = NULL;
 
498
    }
 
499
    return rv;
 
500
}
 
501
 
 
502
 
 
503
/*
 
504
 * This function only works when this process is the active process
 
505
 * (e.g. once it is running a child process, it can no longer determine
 
506
 * which console window is its own.)
 
507
 */
 
508
static BOOL CALLBACK EnumttyWindow(HWND wnd, LPARAM retwnd)
 
509
{
 
510
    char tmp[8];
 
511
    if (GetClassName(wnd, tmp, sizeof(tmp)) && !strcmp(tmp, "tty"))
 
512
    {
 
513
        DWORD wndproc, thisproc = GetCurrentProcessId();
 
514
        GetWindowThreadProcessId(wnd, &wndproc);
 
515
        if (wndproc == thisproc) {
 
516
            *((HWND*)retwnd) = wnd;
 
517
            return FALSE;
 
518
        }
 
519
    }
 
520
    return TRUE;
 
521
}
 
522
 
 
523
 
 
524
/* The remaining code all executes --in the tty's own process context--
 
525
 *
 
526
 * That means special attention must be paid to what it's doing...
 
527
 */
 
528
 
 
529
/* Subclass message process for the tty window
 
530
 *
 
531
 * This code -handles- WM_CLOSE, WM_ENDSESSION and WM_QUERYENDSESSION
 
532
 * by dispatching them to the window identified by the hookwndprop
 
533
 * property atom set against our window.  Messages are then dispatched
 
534
 * to origwndprop property atom we set against the window when we
 
535
 * injected this subclass.  This trick did not work with simply a hook.
 
536
 */
 
537
static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg,
 
538
                                WPARAM wParam, LPARAM lParam)
 
539
{
 
540
    WNDPROC origproc = (WNDPROC) GetProp(hwnd, origwndprop);
 
541
    if (!origproc)
 
542
        return 0;
 
543
 
 
544
    if (msg == WM_NCDESTROY
 
545
        || (msg == hookwndmsg && !LOWORD(wParam) && (HWND)lParam == hwnd))
 
546
    {
 
547
        if (is_subclassed) {
 
548
#ifdef DBG
 
549
            DbgPrintf("W proc %08x hwnd:%08x Subclass removed\r\n",
 
550
                      GetCurrentProcessId(), hwnd);
 
551
#endif
 
552
            if (is_service)
 
553
                RegisterWindows9xService(FALSE);
 
554
            SetWindowLong(hwnd, GWL_WNDPROC, (LONG)origproc);
 
555
            RemoveProp(hwnd, origwndprop);
 
556
            RemoveProp(hwnd, hookwndprop);
 
557
            is_subclassed = FALSE;
 
558
            //if (hmodLock)
 
559
            //    FreeLibrary(hmodLock);
 
560
            //hmodLock = NULL;
 
561
        }
 
562
    }
 
563
    else if (msg == WM_CLOSE || msg == WM_ENDSESSION
 
564
                             || msg == WM_QUERYENDSESSION)
 
565
    {
 
566
        HWND child = (HWND)GetProp(hwnd, hookwndprop);
 
567
        if (child) {
 
568
#ifdef DBG
 
569
            DbgPrintf("W proc %08x hwnd:%08x forwarded msg:%d\r\n",
 
570
                      GetCurrentProcessId(), hwnd, msg);
 
571
#endif
 
572
            return SendMessage(child, msg, wParam, lParam);
 
573
        }
 
574
    }
 
575
    return CallWindowProc(origproc, hwnd, msg, wParam, lParam);
 
576
}
 
577
 
 
578
 
 
579
/* HookProc, once installed, is responsible for subclassing the system
 
580
 * tty windows.  It generally does nothing special itself, since
 
581
 * research indicates that it cannot deal well with the messages we are
 
582
 * interested in, that is, WM_CLOSE, WM_QUERYSHUTDOWN and WM_SHUTDOWN
 
583
 * of the tty process.
 
584
 *
 
585
 * Respond and subclass only when a WM_NULL is received by the window.
 
586
 */
 
587
int HookProc(int hc, HWND *hwnd, UINT *msg, WPARAM *wParam, LPARAM *lParam)
 
588
{
 
589
    if (is_tty == -1 && *hwnd)
 
590
    {
 
591
        char ttybuf[8];
 
592
        HWND htty;
 
593
        hwtty = *hwnd;
 
594
        while (htty = GetParent(hwtty))
 
595
            hwtty = htty;
 
596
        is_tty = (GetClassName(hwtty, ttybuf, sizeof(ttybuf))
 
597
                  && !strcmp(ttybuf, "tty"));
 
598
#ifdef DBG
 
599
        if (is_tty)
 
600
            DbgPrintf("H proc %08x tracking hwnd %08x\r\n",
 
601
                      GetCurrentProcessId(), hwtty);
 
602
#endif
 
603
    }
 
604
 
 
605
    if (*msg == hookwndmsg && *wParam && *lParam == (LPARAM)hwtty && is_tty)
 
606
    {
 
607
        WNDPROC origproc = (WNDPROC)GetWindowLong(hwtty, GWL_WNDPROC);
 
608
        //char myname[MAX_PATH];
 
609
        //if (GetModuleFileName(hmodThis, myname, sizeof(myname)))
 
610
        //    hmodLock = LoadLibrary(myname);
 
611
        SetProp(hwtty, origwndprop, origproc);
 
612
        SetWindowLong(hwtty, GWL_WNDPROC, (LONG)WndProc);
 
613
        is_subclassed = TRUE;
 
614
#ifdef DBG
 
615
        DbgPrintf("H proc %08x hwnd:%08x Subclassed\r\n",
 
616
                  GetCurrentProcessId(), hwtty);
 
617
#endif
 
618
        if (LOWORD(*wParam) == 2)
 
619
            RegisterWindows9xService(TRUE);
 
620
    }
 
621
 
 
622
    return -1;
 
623
}
 
624
 
 
625
 
 
626
/*
 
627
 * PostMessage Hook:
 
628
 */
 
629
LRESULT __declspec(dllexport) CALLBACK GetMsgProc(INT hc, WPARAM wParam,
 
630
                                                  LPARAM lParam)
 
631
{
 
632
    PMSG pmsg;
 
633
 
 
634
    pmsg = (PMSG)lParam;
 
635
 
 
636
    if (pmsg) {
 
637
        int rv = HookProc(hc, &pmsg->hwnd, &pmsg->message,
 
638
                          &pmsg->wParam, &pmsg->lParam);
 
639
        if (rv != -1)
 
640
            return rv;
 
641
    }
 
642
    /*
 
643
     * CallNextHookEx apparently ignores the hhook argument, so pass NULL
 
644
     */
 
645
    return CallNextHookEx(NULL, hc, wParam, lParam);
 
646
}
 
647
 
 
648
 
 
649
/*
 
650
 * SendMessage Hook:
 
651
 */
 
652
LRESULT __declspec(dllexport) CALLBACK CallWndProc(INT hc, WPARAM wParam,
 
653
                                                   LPARAM lParam)
 
654
{
 
655
    PCWPSTRUCT pcwps = (PCWPSTRUCT)lParam;
 
656
 
 
657
    if (pcwps) {
 
658
        int rv = HookProc(hc, &pcwps->hwnd, &pcwps->message,
 
659
                          &pcwps->wParam, &pcwps->lParam);
 
660
        if (rv != -1)
 
661
            return rv;
 
662
    }
 
663
    /*
 
664
     * CallNextHookEx apparently ignores the hhook argument, so pass NULL
 
665
     */
 
666
    return CallNextHookEx(NULL, hc, wParam, lParam);
 
667
}
 
668
 
 
669
 
 
670
#ifdef DBG
 
671
VOID DbgPrintf(
 
672
    LPTSTR fmt,
 
673
    ...
 
674
    )
 
675
{
 
676
    static HANDLE mutex;
 
677
    va_list marker;
 
678
    TCHAR szBuf[256];
 
679
    DWORD t;
 
680
    HANDLE gDbgOut;
 
681
 
 
682
    va_start(marker, fmt);
 
683
    wvsprintf(szBuf, fmt, marker);
 
684
    va_end(marker);
 
685
 
 
686
    if (!mutex)
 
687
        mutex = CreateMutex(NULL, FALSE, "Win9xConHookDbgOut");
 
688
    WaitForSingleObject(mutex, INFINITE);
 
689
    gDbgOut = CreateFile("COM1", GENERIC_READ | GENERIC_WRITE, 0,
 
690
                         NULL, OPEN_EXISTING, FILE_FLAG_WRITE_THROUGH, NULL);
 
691
    WriteFile(gDbgOut, szBuf, strlen(szBuf), &t, NULL);
 
692
    CloseHandle(gDbgOut);
 
693
    ReleaseMutex(mutex);
 
694
}
 
695
#endif
 
696
 
 
697
#endif /* WIN32 */