]> granicus.if.org Git - apache/commitdiff
This is the Win9x console hook handler ... much code to be pulled now
authorWilliam A. Rowe Jr <wrowe@apache.org>
Thu, 30 Nov 2000 01:39:32 +0000 (01:39 +0000)
committerWilliam A. Rowe Jr <wrowe@apache.org>
Thu, 30 Nov 2000 01:39:32 +0000 (01:39 +0000)
  from the src/os/win32/services.c for Win9x.

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@87137 13f79535-47bb-0310-9956-ffa450edef68

server/mpm/winnt/Win9xConHook.c [new file with mode: 0644]
server/mpm/winnt/Win9xConHook.def [new file with mode: 0644]
server/mpm/winnt/Win9xConHook.dsp [new file with mode: 0644]
server/mpm/winnt/Win9xConHook.h [new file with mode: 0644]

diff --git a/server/mpm/winnt/Win9xConHook.c b/server/mpm/winnt/Win9xConHook.c
new file mode 100644 (file)
index 0000000..7f1224a
--- /dev/null
@@ -0,0 +1,517 @@
+/* ====================================================================
+ * Copyright (c) 1995-2000 The Apache Group.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://httpd.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache"
+ *    nor may "Apache" appear in their names without prior written
+ *    permission of the Apache Group.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://httpd.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE APACHE GROUP OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+/*
+ * Win9xConHook.dll - a hook proc to clean up Win95/98 console behavior.
+ *
+ * It is well(?) documented by Microsoft that the Win9x HandlerRoutine
+ * hooked by the SetConsoleCtrlHandler never receives the CTRL_CLOSE_EVENT,
+ * CTRL_LOGOFF_EVENT or CTRL_SHUTDOWN_EVENT signals.  
+ *
+ * It is possible to have a second window to monitor the WM_ENDSESSION 
+ * message, but the close button still fails..
+ * 
+ * There is a 16bit polling method for the close window option, but this
+ * is CPU intensive and requires thunking.
+ *
+ * Attempts to subclass the 'tty' console fail, since that message thread
+ * is actually owned by the 16 bit winoldap.mod process, although the 
+ * window reports it is owned by the process/thread of the console app.
+ *
+ * Win9xConHook is thunks the WM_CLOSE and WM_ENDSESSION messages,
+ * first through a window hook procedure in the winoldap context, into
+ * a subclass WndProc, and on to a second hidden monitor window in the
+ * console application's context that dispatches them to the console app's
+ * registered HandlerRoutine.
+ */
+
+#define DBG 1
+
+#include <windows.h>
+
+/*
+ *  is_tty flags this process;  -1 == unknown, 1 == if tty, 0 == if not
+ *  hw_tty is the handle of the top level tty in this process context
+ *  is_subclassed is toggled to assure DllMain removes the subclass
+ *  is_hooked is toggled to assure DllMain removes the subclass
+ */
+static int is_tty = -1;
+static HWND hwtty = NULL;
+static BOOL is_subclassed = 0;
+
+static HMODULE hmodHook = NULL;
+static HHOOK hhkGetMessage;
+//static HHOOK hhkCallWndProc;
+
+static LPCTSTR origwndprop = NULL;
+static LPCTSTR hookwndprop = NULL;
+
+#ifdef DBG
+static VOID DbgPrintf(LPTSTR fmt, ...);
+#endif
+
+static BOOL CALLBACK EnumttyWindow(HWND wnd, LPARAM retwnd);
+
+
+BOOL __declspec(dllexport) APIENTRY DllMain(PVOID hModule, ULONG ulReason, PCONTEXT pctx)
+{
+    if (ulReason == DLL_PROCESS_ATTACH) 
+    {
+#ifdef DBG
+        DbgPrintf("H ProcessAttach:%8.8x\r\n", GetCurrentProcessId());
+#endif
+        origwndprop = MAKEINTATOM(GlobalAddAtom("Win9xConHookOrigProc"));
+        hookwndprop = MAKEINTATOM(GlobalAddAtom("Win9xConHookThunkWnd"));
+    }
+    else if ( ulReason == DLL_PROCESS_DETACH ) 
+    {
+        HWND parent;
+#ifdef DBG
+        DbgPrintf("H ProcessDetach:%8.8x\r\n", GetCurrentProcessId());                
+#endif
+        if (is_subclassed) {
+            WNDPROC origproc = (WNDPROC) GetProp(hwtty, origwndprop);
+            if (origproc) {
+                SetWindowLong(hwtty, GWL_WNDPROC, (LONG)origproc);
+                RemoveProp(hwtty, origwndprop);
+            }
+        }
+        EnumWindows(EnumttyWindow, (LPARAM)&parent);
+        if (parent) {
+            HWND child = (HWND)GetProp(parent, hookwndprop);
+            if (child)
+                SendMessage(child, WM_DESTROY, 0, 0);
+        }
+        if (hmodHook)
+        {
+            if (hhkGetMessage) {
+                UnhookWindowsHookEx(hhkGetMessage);
+                hhkGetMessage = NULL;
+            }
+            FreeLibrary(hmodHook);
+            hmodHook = NULL;
+        }
+        GlobalDeleteAtom((ATOM)origwndprop);
+        GlobalDeleteAtom((ATOM)hookwndprop);
+    }
+    return TRUE;
+}
+
+
+typedef struct {
+    PHANDLER_ROUTINE phandler;
+    HINSTANCE instance;
+    HWND parent;
+} tty_info;
+
+
+#define gwltty_phandler 0
+#define gwltty_ttywnd 4
+
+/* This is the WndProc procedure for our invisible window.
+ * When our tty subclass WndProc recieves the WM_CLOSE, 
+ * or WM_QUERYENDSESSION messages, we call the installed
+ * HandlerRoutine that was registered with 
+ * If a user logs off, the window is sent WM_QUERYENDSESSION 
+ * as well, but with lParam != 0. We ignore this case.
+ */
+LRESULT CALLBACK ttyConsoleCtrlWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+    if (msg == WM_CREATE)
+    {
+        tty_info *tty = (tty_info*)(((LPCREATESTRUCT)lParam)->lpCreateParams);
+        SetWindowLong(hwnd, gwltty_phandler, (LONG)tty->phandler);
+        SetWindowLong(hwnd, gwltty_ttywnd, (LONG)tty->parent);
+#ifdef DBG
+        DbgPrintf("S Created ttyConHookChild:%8.8x\r\n", hwnd);
+#endif
+        SetProp(((tty_info*)tty)->parent, hookwndprop, hwnd);
+        return 0;
+    }
+    else if (msg == WM_DESTROY)
+    {
+        HWND parent = (HWND)GetWindowLong(hwnd, gwltty_ttywnd);
+        RemoveProp(parent, hookwndprop);
+    }
+    else if (msg == WM_CLOSE)
+    {
+        PHANDLER_ROUTINE phandler = 
+            (PHANDLER_ROUTINE)GetWindowLong(hwnd, gwltty_phandler);
+#ifdef DBG
+        DbgPrintf("S Invoking CTRL_CLOSE_EVENT:%8.8x\r\n",
+                  GetCurrentProcessId());
+#endif
+        return !phandler(CTRL_CLOSE_EVENT);
+    }
+    else if (msg == WM_QUERYENDSESSION)
+    {
+        if (lParam & ENDSESSION_LOGOFF) 
+        {
+            PHANDLER_ROUTINE phandler = 
+                (PHANDLER_ROUTINE)GetWindowLong(hwnd, gwltty_phandler);
+#ifdef DBG
+            DbgPrintf("S Invoking CTRL_LOGOFF_EVENT:%8.8x\r\n",
+                      GetCurrentProcessId());
+#endif
+            return !phandler(CTRL_LOGOFF_EVENT);
+        }
+        else
+        {
+            PHANDLER_ROUTINE phandler = 
+                (PHANDLER_ROUTINE)GetWindowLong(hwnd, gwltty_phandler);
+#ifdef DBG
+            DbgPrintf("S Invoking CTRL_SHUTDOWN_EVENT:%8.8x\r\n",
+                      GetCurrentProcessId());
+#endif
+            return !phandler(CTRL_SHUTDOWN_EVENT);
+        }
+    }
+    return (DefWindowProc(hwnd, msg, wParam, lParam));
+}
+
+
+DWORD WINAPI ttyConsoleCtrlThread(LPVOID tty)
+{
+    /* When running as a service under Windows 9x, ConsoleCtrlHandler 
+     * does not respond properly when the user logs off or the system 
+     * is shutdown.  If the WatchWindow thread is created with a NULL
+     * service_name argument, then the ...SystemMonitor window class is
+     * used to create the "Apache" window to watch for logoff and shutdown.
+     * If the service_name is provided, the ...ServiceMonitor window class
+     * is used to create the window named by the service_name argument,
+     * and the logoff message is ignored.
+     */
+    WNDCLASS wc;
+    HWND hwnd;
+    MSG msg;
+    wc.style         = CS_GLOBALCLASS;
+    wc.lpfnWndProc   = ttyConsoleCtrlWndProc; 
+    wc.cbClsExtra    = 0;
+    wc.cbWndExtra    = 8; 
+    wc.hInstance     = NULL;
+    wc.hIcon         = NULL;
+    wc.hCursor       = NULL;
+    wc.hbrBackground = NULL;
+    wc.lpszMenuName  = NULL;
+    wc.lpszClassName = "ttyConHookChild";
+    
+    if (!RegisterClass(&wc)) { 
+#ifdef DBG
+        DbgPrintf("S Created ttyConHookChild class\r\n");
+#endif
+        return 0;
+    }
+
+    /* Create an invisible window */
+    hwnd = CreateWindow(wc.lpszClassName, "", 
+                        WS_OVERLAPPED & ~WS_VISIBLE,
+                        CW_USEDEFAULT, CW_USEDEFAULT, 
+                        CW_USEDEFAULT, CW_USEDEFAULT, 
+                        NULL, NULL, 
+                        ((tty_info*)tty)->instance, tty);
+
+    if (!hwnd) {
+#ifdef DBG
+        DbgPrintf("S Error Creating ttyConHookChild:%d\r\n", GetLastError());
+#endif
+        return 0;
+    }
+
+    while (GetMessage(&msg, NULL, 0, 0)) 
+    {
+        TranslateMessage(&msg);
+        DispatchMessage(&msg);
+        if (msg.message == WM_DESTROY)
+            DestroyWindow(hwnd);
+    }
+    return 0;
+}
+
+
+/* 
+ * This function only works when this process is the active process 
+ * (e.g. once it is running a child process, it can no longer determine 
+ * which console window is its own.)
+ */
+static BOOL CALLBACK EnumttyWindow(HWND wnd, LPARAM retwnd)
+{
+    char tmp[4];
+    if (GetClassName(wnd, tmp, sizeof(tmp)) && !strcmp(tmp, "tty")) 
+    {
+        DWORD wndproc, thisproc = GetCurrentProcessId();
+        GetWindowThreadProcessId(wnd, &wndproc);
+        if (wndproc == thisproc) {
+            *((HWND*)retwnd) = wnd;
+            return FALSE;
+        }
+    }
+    return TRUE;
+}
+
+
+/*
+ * Exported function that sets up the fixup child window and dispatch
+ */
+BOOL __declspec(dllexport) WINAPI FixConsoleCtrlHandler(
+        PHANDLER_ROUTINE phandler,
+        BOOL add)
+{
+    HWND parent;
+    EnumWindows(EnumttyWindow, (LPARAM)&parent);
+
+    if (!parent)
+        return FALSE;
+
+    if (add)
+    {
+        HANDLE hThread;
+        DWORD tid;
+        static tty_info tty;
+        tty.phandler = phandler;
+        tty.parent = parent;
+        tty.instance = GetModuleHandle(NULL);
+
+        hmodHook = LoadLibrary("Win9xConHook.dll");
+        if (hmodHook)
+        {
+            hhkGetMessage = SetWindowsHookEx(WH_GETMESSAGE,
+                (HOOKPROC)GetProcAddress(hmodHook, "GetMsgProc"), hmodHook, 0);
+            //hhkCallWndProc = SetWindowsHookEx(WH_CALLWNDPROC,
+            //    (HOOKPROC)GetProcAddress(hmodHook, "CallWndProc"), hmodHook, 0);
+        }
+        
+        hThread = CreateThread(NULL, 0, ttyConsoleCtrlThread,
+                               (LPVOID)&tty, 0, &tid);
+        if (hThread)
+        {
+            CloseHandle(hThread);
+            return TRUE;
+        }
+    }
+    else /* remove */
+    {
+        HWND child = FindWindowEx(parent, NULL, "ttyConHookChild", NULL);
+        if (child)
+            SendMessage(child, WM_DESTROY, 0, 0);
+        if (hmodHook)
+        {
+            if (hhkGetMessage) {
+                UnhookWindowsHookEx(hhkGetMessage);
+                hhkGetMessage = NULL;
+            }
+            FreeLibrary(hmodHook);
+            hmodHook = NULL;
+        }
+        return TRUE;
+    }
+    return FALSE;
+}
+
+
+/*
+ * Subclass message process for the tty window
+ */
+LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+    WNDPROC origproc = (WNDPROC) GetProp(hwnd, origwndprop);
+    if (!origproc)
+        return 0;
+
+    switch (msg)
+    {
+        case WM_NCDESTROY:
+#ifdef DBG
+            DbgPrintf("W Proc %08x hwnd:%08x Subclass removed\r\n", 
+                      GetCurrentProcessId(), hwnd);
+#endif
+            is_subclassed = FALSE;
+            SetWindowLong(hwnd, GWL_WNDPROC, (LONG)origproc);
+            RemoveProp(hwnd, origwndprop);
+            break;
+
+        case WM_CLOSE:
+        case WM_ENDSESSION:
+        case WM_QUERYENDSESSION:
+        {
+            HWND child = (HWND)GetProp(hwnd, hookwndprop);
+#ifdef DBG
+            DbgPrintf("W Proc %08x hwnd:%08x msg:%d\r\n", 
+                      GetCurrentProcessId(), hwnd, msg);
+#endif
+            if (!child)
+                break;
+            return SendMessage(child, msg, wParam, lParam);
+        }
+    }
+    return CallWindowProc(origproc, hwnd, msg, wParam, lParam);
+}
+
+
+int HookProc(int hc, HWND *hwnd, UINT *msg, WPARAM *wParam, LPARAM *lParam)
+{
+    if (is_tty == -1 && *hwnd) 
+    {
+        char ttybuf[4];
+        HWND htty;
+        hwtty = *hwnd;
+        while (htty = GetParent(hwtty))
+            hwtty = htty;
+        is_tty = (GetClassName(hwtty, ttybuf, sizeof(ttybuf)) 
+                  && !strcmp(ttybuf, "tty"));
+        if (is_tty)
+        {
+            WNDPROC origproc = (WNDPROC)GetWindowLong(hwtty, GWL_WNDPROC);
+            SetProp(hwtty, origwndprop, origproc);
+            SetWindowLong(hwtty, GWL_WNDPROC, (LONG)WndProc);
+            is_subclassed = TRUE;
+#ifdef DBG
+            DbgPrintf("W Proc %08x hwnd:%08x Subclassed\r\n", 
+                      GetCurrentProcessId(), hwtty);
+#endif
+        }
+#ifdef DBG
+        DbgPrintf("H Proc %08x %s %08x\r\n", GetCurrentProcessId(), 
+                  is_tty ? "tracking" : "ignoring", hwtty);
+#endif
+    }
+
+    if (hc >= 0 && is_tty && *hwnd == hwtty)
+    {
+        if ((*msg == WM_CLOSE)
+         || (*msg == WM_ENDSESSION)) {
+            DWORD apppid, ttypid = GetCurrentProcessId();
+            GetWindowThreadProcessId(*hwnd, &apppid);
+#ifdef DBG
+            DbgPrintf("H Proc %08x hwnd:%08x owned by %08x msg:%d\r\n", ttypid, *hwnd, apppid, *msg);
+#endif
+            //*msg = WM_NULL;
+            /*
+             * Experimental, return 0 or 1 will bypass the next hook and return that
+             * value from the hook procedure, -1 continues to call the next hook.
+             */
+            return -1;
+        }
+    }
+    return -1;
+}
+
+
+/*
+ * PostMessage Hook:
+ */
+LRESULT __declspec(dllexport) CALLBACK GetMsgProc(INT hc, WPARAM wParam, LPARAM lParam)
+{
+    PMSG pmsg;
+
+    pmsg = (PMSG)lParam;
+
+    if (pmsg) {
+        int rv = HookProc(hc, &pmsg->hwnd, &pmsg->message, &pmsg->lParam, &pmsg->wParam);
+        if (rv != -1)
+            return rv;
+    }
+    /* 
+     * CallNextHookEx apparently ignores the hhook argument, so pass NULL
+     */
+    return CallNextHookEx(NULL, hc, wParam, lParam);
+}
+
+
+/*
+ * SendMessage Hook:
+ */
+LRESULT __declspec(dllexport) CALLBACK CallWndProc(INT hc, WPARAM wParam, LPARAM lParam)
+{
+    PCWPSTRUCT pcwps = (PCWPSTRUCT)lParam;
+    
+    if (pcwps) {
+        int rv = HookProc(hc, &pcwps->hwnd, &pcwps->message, &pcwps->wParam, &pcwps->lParam);
+        if (rv != -1)
+            return rv;
+    }
+    /* 
+     * CallNextHookEx apparently ignores the hhook argument, so pass NULL
+     */
+    return CallNextHookEx(NULL, hc, wParam, lParam);
+}
+
+
+#ifdef DBG
+VOID DbgPrintf(
+    LPTSTR fmt,
+    ...
+    )
+{
+    va_list marker;
+    TCHAR szBuf[256];
+    DWORD t;
+    HANDLE gDbgOut;
+
+    va_start(marker, fmt);
+    wvsprintf(szBuf, fmt, marker);
+    va_end(marker);
+
+    gDbgOut = CreateFile("COM1", GENERIC_READ | GENERIC_WRITE, 
+                         FILE_SHARE_READ | FILE_SHARE_WRITE,
+                         NULL, OPEN_EXISTING, FILE_FLAG_WRITE_THROUGH, NULL);
+    WriteFile(gDbgOut, szBuf, strlen(szBuf), &t, NULL);
+    CloseHandle(gDbgOut);
+}
+#endif
+
+
diff --git a/server/mpm/winnt/Win9xConHook.def b/server/mpm/winnt/Win9xConHook.def
new file mode 100644 (file)
index 0000000..689eb75
--- /dev/null
@@ -0,0 +1,9 @@
+LIBRARY Win9xConHook
+
+EXETYPE WINDOWS
+
+EXPORTS
+    DllMain
+    GetMsgProc
+    CallWndProc
+    FixConsoleCtrlHandler
\ No newline at end of file
diff --git a/server/mpm/winnt/Win9xConHook.dsp b/server/mpm/winnt/Win9xConHook.dsp
new file mode 100644 (file)
index 0000000..3704f5b
--- /dev/null
@@ -0,0 +1,103 @@
+# Microsoft Developer Studio Project File - Name="Win9xConHook" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+
+CFG=Win9xConHook - Win32 Release
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "Win9xConHook.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "Win9xConHook.mak" CFG="Win9xConHook - Win32 Release"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "Win9xConHook - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "Win9xConHook - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "Win9xConHook - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir ".\Release"
+# PROP BASE Intermediate_Dir ".\Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Win9xConHookR"
+# PROP Intermediate_Dir "Win9xConHookR"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /c
+# ADD CPP /nologo /MD /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "SHARED_MODULE" /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x809 /d "NDEBUG"
+# ADD RSC /l 0x809 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386 /base:@"BaseAddr.ref",mod_status
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib /nologo /base:"0x1c0f0000" /subsystem:windows /dll /map /machine:I386
+
+!ELSEIF  "$(CFG)" == "Win9xConHook - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir ".\Debug"
+# PROP BASE Intermediate_Dir ".\Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Win9xConHookD"
+# PROP Intermediate_Dir "Win9xConHookD"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /c
+# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "SHARED_MODULE" /FD /c
+# ADD BASE MTL /nologo /D "_DEBUG" /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x809 /d "_DEBUG"
+# ADD RSC /l 0x809 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /base:@"BaseAddr.ref",mod_status
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib /nologo /base:"0x1c0f0000" /subsystem:windows /dll /incremental:no /map /debug /machine:I386
+
+!ENDIF 
+
+# Begin Target
+
+# Name "Win9xConHook - Win32 Release"
+# Name "Win9xConHook - Win32 Debug"
+# Begin Source File
+
+SOURCE=.\Win9xConHook.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\Win9xConHook.def
+# End Source File
+# Begin Source File
+
+SOURCE=.\Win9xConHook.h
+# End Source File
+# End Target
+# End Project
diff --git a/server/mpm/winnt/Win9xConHook.h b/server/mpm/winnt/Win9xConHook.h
new file mode 100644 (file)
index 0000000..107cdbe
--- /dev/null
@@ -0,0 +1,24 @@
+
+
+
+/*
+ * FixConsoleControlHandler will register a handler routine with the
+ * Win9xConHook.dll, creating a hidden window and forwarding the
+ * WM_ENDSESSION and WM_CLOSE messages to the registered handler
+ * as CTRL_SHUTDOWN_EVENT, CTRL_LOGOFF_EVENT and CTRL_CLOSE_EVENT. 
+ */
+BOOL WINAPI FixConsoleCtrlHandler(
+        PHANDLER_ROUTINE phandler,
+        BOOL add);
+
+/*
+ * PostMessage Hook:
+ */
+LRESULT CALLBACK GetMsgProc(INT hc, WPARAM wParam, LPARAM lParam);
+
+
+/*
+ * SendMessage Hook:
+ */
+LRESULT CALLBACK CallWndProc(INT hc, WPARAM wParam, LPARAM lParam);
+