Return-Path: Delivered-To: apmail-apache-cvs-archive@apache.org Received: (qmail 53856 invoked by uid 500); 30 Nov 2000 01:39:43 -0000 Mailing-List: contact apache-cvs-help@apache.org; run by ezmlm Precedence: bulk Reply-To: new-httpd@apache.org list-help: list-unsubscribe: list-post: Delivered-To: mailing list apache-cvs@apache.org Received: (qmail 53738 invoked by uid 500); 30 Nov 2000 01:39:40 -0000 Delivered-To: apmail-apache-1.3-cvs@apache.org Date: 30 Nov 2000 01:39:39 -0000 Message-ID: <20001130013939.53723.qmail@locus.apache.org> From: wrowe@locus.apache.org To: apache-1.3-cvs@apache.org Subject: cvs commit: apache-1.3/src/os/win32/win9xconhook Win9xConHook.def Win9xConHook.h Win9xConHook.c Win9xConHook.dsp wrowe 00/11/29 17:39:33 Added: src/os/win32/win9xconhook Win9xConHook.def Win9xConHook.h Win9xConHook.c Win9xConHook.dsp Log: This is the Win9x console hook handler ... much code to be pulled now from the src/os/win32/services.c for Win9x. Revision Changes Path 1.1 apache-1.3/src/os/win32/win9xconhook/Win9xConHook.def Index: Win9xConHook.def =================================================================== LIBRARY Win9xConHook EXETYPE WINDOWS EXPORTS DllMain GetMsgProc CallWndProc FixConsoleCtrlHandler 1.1 apache-1.3/src/os/win32/win9xconhook/Win9xConHook.h Index: Win9xConHook.h =================================================================== /* * 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); 1.1 apache-1.3/src/os/win32/win9xconhook/Win9xConHook.c Index: Win9xConHook.c =================================================================== /* ==================================================================== * 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 . * */ /* * 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 /* * 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 1.1 apache-1.3/src/os/win32/win9xconhook/Win9xConHook.dsp Index: Win9xConHook.dsp =================================================================== # 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