Commit bdf180c3 authored by William A. Rowe Jr's avatar William A. Rowe Jr
Browse files

  This is the Win9x console hook handler ... much code to be pulled now
  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
parent 4f1f6d32
Loading
Loading
Loading
Loading
+517 −0
Original line number Diff line number Diff line
/* ====================================================================
 * 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

+9 −0
Original line number Diff line number Diff line
LIBRARY Win9xConHook

EXETYPE WINDOWS

EXPORTS
    DllMain
    GetMsgProc
    CallWndProc
    FixConsoleCtrlHandler
 No newline at end of file
+103 −0
Original line number Diff line number Diff line
# 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
+24 −0
Original line number Diff line number Diff line



/*
 * 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);