summaryrefslogtreecommitdiffstats
path: root/rubbos/app/httpd-2.0.64/server/mpm/winnt/Win9xConHook.c
diff options
context:
space:
mode:
Diffstat (limited to 'rubbos/app/httpd-2.0.64/server/mpm/winnt/Win9xConHook.c')
-rw-r--r--rubbos/app/httpd-2.0.64/server/mpm/winnt/Win9xConHook.c697
1 files changed, 697 insertions, 0 deletions
diff --git a/rubbos/app/httpd-2.0.64/server/mpm/winnt/Win9xConHook.c b/rubbos/app/httpd-2.0.64/server/mpm/winnt/Win9xConHook.c
new file mode 100644
index 00000000..a352dd1b
--- /dev/null
+++ b/rubbos/app/httpd-2.0.64/server/mpm/winnt/Win9xConHook.c
@@ -0,0 +1,697 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifdef WIN32
+
+/*
+ * 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.
+ */
+
+/* This debugging define turns on output to COM1, although you better init
+ * the port first (even using hyperterm). It's the only way to catch the
+ * goings on within system logoff/shutdown.
+ * #define DBG 1
+ */
+
+#include <windows.h>
+
+/* Variables used within any process context:
+ * hookwndmsg is a shared message to send Win9xConHook signals
+ * origwndprop is a wndprop atom to store the orig wndproc of the tty
+ * hookwndprop is a wndprop atom to store the hwnd of the hidden child
+ * is_service reminds us to unmark this process on the way out
+ */
+static UINT hookwndmsg = 0;
+static LPCTSTR origwndprop;
+static LPCTSTR hookwndprop;
+static BOOL is_service = 0;
+//static HMODULE hmodThis = NULL;
+
+/* Variables used within the tty processes' context:
+ * 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 on unload
+ * hmodLock is there to try and prevent this dll from being unloaded if the
+ * hook is removed while we are subclassed
+ */
+static int is_tty = -1;
+static HWND hwtty = NULL;
+static BOOL is_subclassed = 0;
+
+// This simply causes a gpfault the moment it tries to FreeLibrary within
+// the subclass procedure ... not good.
+//static HMODULE hmodLock = NULL;
+
+/* Variables used within the service or console app's context:
+ * hmodHook is the instance handle of this module for registering the hooks
+ * hhkGetMessage is the hook handle for catching Posted messages
+ * hhkGetMessage is the hook handle for catching Sent messages
+ * monitor_hwnd is the invisible window that handles our tty messages
+ * the tty_info strucure is used to pass args into the hidden window's thread
+ */
+static HMODULE hmodHook = NULL;
+static HHOOK hhkGetMessage;
+//static HHOOK hhkCallWndProc;
+static HWND monitor_hwnd = NULL;
+
+typedef struct {
+ PHANDLER_ROUTINE phandler;
+ HINSTANCE instance;
+ HWND parent;
+ INT type;
+ LPCSTR name;
+} tty_info;
+
+/* These are the GetWindowLong offsets for the hidden window's internal info
+ * gwltty_phandler is the address of the app's HandlerRoutine
+ * gwltty_ttywnd is the tty this hidden window will handle messages from
+ */
+#define gwltty_phandler 0
+#define gwltty_ttywnd 4
+
+/* Forward declaration prototypes for internal functions
+ */
+static BOOL CALLBACK EnumttyWindow(HWND wnd, LPARAM retwnd);
+static LRESULT WINAPI RegisterWindows9xService(BOOL set_service);
+static LRESULT CALLBACK ttyConsoleCtrlWndProc(HWND hwnd, UINT msg,
+ WPARAM wParam, LPARAM lParam);
+static DWORD WINAPI ttyConsoleCtrlThread(LPVOID tty);
+static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg,
+ WPARAM wParam, LPARAM lParam);
+static int HookProc(int hc, HWND *hwnd, UINT *msg,
+ WPARAM *wParam, LPARAM *lParam);
+#ifdef DBG
+static VOID DbgPrintf(LPTSTR fmt, ...);
+#endif
+
+
+/* DllMain is invoked by every process in the entire system that is hooked
+ * by our window hooks, notably the tty processes' context, and by the user
+ * who wants tty messages (the app). Keep it light and simple.
+ */
+BOOL __declspec(dllexport) APIENTRY DllMain(HINSTANCE hModule, ULONG ulReason,
+ LPVOID pctx)
+{
+ if (ulReason == DLL_PROCESS_ATTACH)
+ {
+ //hmodThis = hModule;
+ if (!hookwndmsg) {
+ origwndprop = MAKEINTATOM(GlobalAddAtom("Win9xConHookOrigProc"));
+ hookwndprop = MAKEINTATOM(GlobalAddAtom("Win9xConHookThunkWnd"));
+ hookwndmsg = RegisterWindowMessage("Win9xConHookMsg");
+ }
+#ifdef DBG
+// DbgPrintf("H ProcessAttach:%8.8x\r\n",
+// GetCurrentProcessId());
+#endif
+ }
+ else if ( ulReason == DLL_PROCESS_DETACH )
+ {
+#ifdef DBG
+// DbgPrintf("H ProcessDetach:%8.8x\r\n", GetCurrentProcessId());
+#endif
+ if (monitor_hwnd)
+ SendMessage(monitor_hwnd, WM_DESTROY, 0, 0);
+ if (is_subclassed)
+ SendMessage(hwtty, hookwndmsg, 0, (LPARAM)hwtty);
+ if (hmodHook)
+ {
+ if (hhkGetMessage) {
+ UnhookWindowsHookEx(hhkGetMessage);
+ hhkGetMessage = NULL;
+ }
+ //if (hhkCallWndProc) {
+ // UnhookWindowsHookEx(hhkCallWndProc);
+ // hhkCallWndProc = NULL;
+ //}
+ FreeLibrary(hmodHook);
+ hmodHook = NULL;
+ }
+ if (is_service)
+ RegisterWindows9xService(FALSE);
+ if (hookwndmsg) {
+ GlobalDeleteAtom((ATOM)origwndprop);
+ GlobalDeleteAtom((ATOM)hookwndprop);
+ hookwndmsg = 0;
+ }
+ }
+ return TRUE;
+}
+
+
+/* This group of functions are provided for the service/console app
+ * to register itself a HandlerRoutine to accept tty or service messages
+ */
+
+
+/* Exported function that creates a Win9x 'service' via a hidden window,
+ * that notifies the process via the HandlerRoutine messages.
+ */
+BOOL __declspec(dllexport) WINAPI Windows9xServiceCtrlHandler(
+ PHANDLER_ROUTINE phandler,
+ LPCSTR name)
+{
+ /* If we have not yet done so */
+ FreeConsole();
+
+ if (name)
+ {
+ DWORD tid;
+ HANDLE hThread;
+ /* NOTE: this is static so the module can continue to
+ * access these args while we go on to other things
+ */
+ static tty_info tty;
+ tty.instance = GetModuleHandle(NULL);
+ tty.phandler = phandler;
+ tty.parent = NULL;
+ tty.name = name;
+ tty.type = 2;
+ RegisterWindows9xService(TRUE);
+ hThread = CreateThread(NULL, 0, ttyConsoleCtrlThread,
+ (LPVOID)&tty, 0, &tid);
+ if (hThread)
+ {
+ CloseHandle(hThread);
+ return TRUE;
+ }
+ }
+ else /* remove */
+ {
+ if (monitor_hwnd)
+ SendMessage(monitor_hwnd, WM_DESTROY, 0, 0);
+ RegisterWindows9xService(FALSE);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+/* Exported function that registers a HandlerRoutine to accept missing
+ * Win9x CTRL_EVENTs from the tty window, as NT does without a hassle.
+ * If add is 1 or 2, register the handler, if 2 also mark it as a service.
+ * If add is 0 deregister the handler, and unmark if a service
+ */
+BOOL __declspec(dllexport) WINAPI FixConsoleCtrlHandler(
+ PHANDLER_ROUTINE phandler,
+ INT add)
+{
+ HWND parent;
+
+ if (add)
+ {
+ HANDLE hThread;
+ DWORD tid;
+ /* NOTE: this is static so the module can continue to
+ * access these args while we go on to other things
+ */
+ static tty_info tty;
+ EnumWindows(EnumttyWindow, (LPARAM)&parent);
+ if (!parent) {
+#ifdef DBG
+ DbgPrintf("A EnumttyWindow failed (%d)\r\n", GetLastError());
+#endif
+ return FALSE;
+ }
+ tty.instance = GetModuleHandle(NULL);
+ tty.phandler = phandler;
+ tty.parent = parent;
+ tty.type = add;
+ if (add == 2) {
+ tty.name = "ttyService";
+ RegisterWindows9xService(TRUE);
+ }
+ else
+ tty.name = "ttyMonitor";
+ hThread = CreateThread(NULL, 0, ttyConsoleCtrlThread,
+ (LPVOID)&tty, 0, &tid);
+ if (!hThread)
+ return FALSE;
+ CloseHandle(hThread);
+ 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);
+ }
+ return TRUE;
+ }
+ else /* remove */
+ {
+ if (monitor_hwnd) {
+ SendMessage(monitor_hwnd, WM_DESTROY, 0, 0);
+ }
+ if (hmodHook)
+ {
+ if (hhkGetMessage) {
+ UnhookWindowsHookEx(hhkGetMessage);
+ hhkGetMessage = NULL;
+ }
+ //if (hhkCallWndProc) {
+ // UnhookWindowsHookEx(hhkCallWndProc);
+ // hhkCallWndProc = NULL;
+ //}
+ FreeLibrary(hmodHook);
+ hmodHook = NULL;
+ }
+ if (is_service)
+ RegisterWindows9xService(FALSE);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+/* The following internal helpers are only used within the app's context
+ */
+
+/* ttyConsoleCreateThread is the process that runs within the user app's
+ * context. It creates and pumps the messages of a hidden monitor window,
+ * watching for messages from the system, or the associated subclassed tty
+ * window. Things can happen in our context that can't be done from the
+ * tty's context, and visa versa, so the subclass procedure and this hidden
+ * window work together to make it all happen.
+ */
+static DWORD WINAPI ttyConsoleCtrlThread(LPVOID tty)
+{
+ WNDCLASS wc;
+ 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;
+ if (((tty_info*)tty)->parent)
+ wc.lpszClassName = "ttyConHookChild";
+ else
+ wc.lpszClassName = "ApacheWin95ServiceMonitor";
+
+ if (!RegisterClass(&wc)) {
+#ifdef DBG
+ DbgPrintf("A proc %8.8x Error creating class %s (%d)\r\n",
+ GetCurrentProcessId(), wc.lpszClassName, GetLastError());
+#endif
+ return 0;
+ }
+
+ /* Create an invisible window */
+ monitor_hwnd = CreateWindow(wc.lpszClassName, ((tty_info*)tty)->name,
+ WS_OVERLAPPED & ~WS_VISIBLE,
+ CW_USEDEFAULT, CW_USEDEFAULT,
+ CW_USEDEFAULT, CW_USEDEFAULT,
+ NULL, NULL,
+ ((tty_info*)tty)->instance, tty);
+
+ if (!monitor_hwnd) {
+#ifdef DBG
+ DbgPrintf("A proc %8.8x Error creating window %s %s (%d)\r\n",
+ GetCurrentProcessId(), wc.lpszClassName,
+ ((tty_info*)tty)->name, GetLastError());
+#endif
+ return 0;
+ }
+
+ while (GetMessage(&msg, NULL, 0, 0))
+ {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+
+ /* Tag again as deleted, just in case we missed WM_DESTROY */
+ monitor_hwnd = NULL;
+ return 0;
+}
+
+
+/* This is the WndProc procedure for our invisible window.
+ * When our subclasssed tty window receives the WM_CLOSE, WM_ENDSESSION,
+ * or WM_QUERYENDSESSION messages, the message is dispatched to our hidden
+ * window (this message process), and we call the installed HandlerRoutine
+ * that was registered by the app.
+ */
+static 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("A proc %8.8x created %8.8x %s for tty wnd %8.8x\r\n",
+ GetCurrentProcessId(), hwnd,
+ tty->name, tty->parent);
+#endif
+ if (tty->parent) {
+ SetProp(tty->parent, hookwndprop, hwnd);
+ PostMessage(tty->parent, hookwndmsg,
+ tty->type, (LPARAM)tty->parent);
+ }
+ return 0;
+ }
+ else if (msg == WM_DESTROY)
+ {
+ HWND parent = (HWND)GetWindowLong(hwnd, gwltty_ttywnd);
+#ifdef DBG
+ DbgPrintf("A proc %8.8x destroyed %8.8x ttyConHookChild\r\n",
+ GetCurrentProcessId(), hwnd);
+#endif
+ if (parent) {
+ RemoveProp(parent, hookwndprop);
+ SendMessage(parent, hookwndmsg, 0, (LPARAM)parent);
+ }
+ monitor_hwnd = NULL;
+ }
+ else if (msg == WM_CLOSE)
+ {
+ PHANDLER_ROUTINE phandler =
+ (PHANDLER_ROUTINE)GetWindowLong(hwnd, gwltty_phandler);
+ LRESULT rv = phandler(CTRL_CLOSE_EVENT);
+#ifdef DBG
+ DbgPrintf("A proc %8.8x invoked CTRL_CLOSE_EVENT "
+ "returning %d\r\n",
+ GetCurrentProcessId(), rv);
+#endif
+ if (rv)
+ return !rv;
+ }
+ else if ((msg == WM_QUERYENDSESSION) || (msg == WM_ENDSESSION))
+ {
+ if (lParam & ENDSESSION_LOGOFF)
+ {
+ PHANDLER_ROUTINE phandler =
+ (PHANDLER_ROUTINE)GetWindowLong(hwnd, gwltty_phandler);
+ LRESULT rv = phandler(CTRL_LOGOFF_EVENT);
+#ifdef DBG
+ DbgPrintf("A proc %8.8x invoked CTRL_LOGOFF_EVENT "
+ "returning %d\r\n",
+ GetCurrentProcessId(), rv);
+#endif
+ if (rv)
+ return ((msg == WM_QUERYENDSESSION) ? rv : !rv);
+ }
+ else
+ {
+ PHANDLER_ROUTINE phandler =
+ (PHANDLER_ROUTINE)GetWindowLong(hwnd, gwltty_phandler);
+ LRESULT rv = phandler(CTRL_SHUTDOWN_EVENT);
+#ifdef DBG
+ DbgPrintf("A proc %8.8x invoked CTRL_SHUTDOWN_EVENT "
+ "returning %d\r\n", GetCurrentProcessId(), rv);
+#endif
+ if (rv)
+ return ((msg == WM_QUERYENDSESSION) ? rv : !rv);
+ }
+ }
+ return (DefWindowProc(hwnd, msg, wParam, lParam));
+}
+
+
+/* The following internal helpers are invoked by the hooked tty and our app
+ */
+
+
+/* Register or deregister the current process as a Windows9x style service.
+ * Experience shows this call is ignored across processes, so the second
+ * arg to RegisterServiceProcess (process group id) is effectively useless.
+ */
+static LRESULT WINAPI RegisterWindows9xService(BOOL set_service)
+{
+ static HINSTANCE hkernel;
+ static DWORD (WINAPI *register_service_process)(DWORD, DWORD) = NULL;
+ BOOL rv;
+
+ if (set_service == is_service)
+ return 1;
+
+#ifdef DBG
+ DbgPrintf("R %s proc %8.8x as a service\r\n",
+ set_service ? "installing" : "removing",
+ GetCurrentProcessId());
+#endif
+
+ if (!register_service_process)
+ {
+ /* Obtain a handle to the kernel library */
+ hkernel = LoadLibrary("KERNEL32.DLL");
+ if (!hkernel)
+ return 0;
+
+ /* Find the RegisterServiceProcess function */
+ register_service_process = (DWORD (WINAPI *)(DWORD, DWORD))
+ GetProcAddress(hkernel, "RegisterServiceProcess");
+ if (register_service_process == NULL) {
+ FreeLibrary(hkernel);
+ return 0;
+ }
+ }
+
+ /* Register this process as a service */
+ rv = register_service_process(0, set_service != FALSE);
+ if (rv)
+ is_service = set_service;
+
+ if (!is_service)
+ {
+ /* Unload the kernel library */
+ FreeLibrary(hkernel);
+ register_service_process = NULL;
+ }
+ return rv;
+}
+
+
+/*
+ * 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[8];
+ 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;
+}
+
+
+/* The remaining code all executes --in the tty's own process context--
+ *
+ * That means special attention must be paid to what it's doing...
+ */
+
+/* Subclass message process for the tty window
+ *
+ * This code -handles- WM_CLOSE, WM_ENDSESSION and WM_QUERYENDSESSION
+ * by dispatching them to the window identified by the hookwndprop
+ * property atom set against our window. Messages are then dispatched
+ * to origwndprop property atom we set against the window when we
+ * injected this subclass. This trick did not work with simply a hook.
+ */
+static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg,
+ WPARAM wParam, LPARAM lParam)
+{
+ WNDPROC origproc = (WNDPROC) GetProp(hwnd, origwndprop);
+ if (!origproc)
+ return 0;
+
+ if (msg == WM_NCDESTROY
+ || (msg == hookwndmsg && !LOWORD(wParam) && (HWND)lParam == hwnd))
+ {
+ if (is_subclassed) {
+#ifdef DBG
+ DbgPrintf("W proc %08x hwnd:%08x Subclass removed\r\n",
+ GetCurrentProcessId(), hwnd);
+#endif
+ if (is_service)
+ RegisterWindows9xService(FALSE);
+ SetWindowLong(hwnd, GWL_WNDPROC, (LONG)origproc);
+ RemoveProp(hwnd, origwndprop);
+ RemoveProp(hwnd, hookwndprop);
+ is_subclassed = FALSE;
+ //if (hmodLock)
+ // FreeLibrary(hmodLock);
+ //hmodLock = NULL;
+ }
+ }
+ else if (msg == WM_CLOSE || msg == WM_ENDSESSION
+ || msg == WM_QUERYENDSESSION)
+ {
+ HWND child = (HWND)GetProp(hwnd, hookwndprop);
+ if (child) {
+#ifdef DBG
+ DbgPrintf("W proc %08x hwnd:%08x forwarded msg:%d\r\n",
+ GetCurrentProcessId(), hwnd, msg);
+#endif
+ return SendMessage(child, msg, wParam, lParam);
+ }
+ }
+ return CallWindowProc(origproc, hwnd, msg, wParam, lParam);
+}
+
+
+/* HookProc, once installed, is responsible for subclassing the system
+ * tty windows. It generally does nothing special itself, since
+ * research indicates that it cannot deal well with the messages we are
+ * interested in, that is, WM_CLOSE, WM_QUERYSHUTDOWN and WM_SHUTDOWN
+ * of the tty process.
+ *
+ * Respond and subclass only when a WM_NULL is received by the window.
+ */
+int HookProc(int hc, HWND *hwnd, UINT *msg, WPARAM *wParam, LPARAM *lParam)
+{
+ if (is_tty == -1 && *hwnd)
+ {
+ char ttybuf[8];
+ HWND htty;
+ hwtty = *hwnd;
+ while (htty = GetParent(hwtty))
+ hwtty = htty;
+ is_tty = (GetClassName(hwtty, ttybuf, sizeof(ttybuf))
+ && !strcmp(ttybuf, "tty"));
+#ifdef DBG
+ if (is_tty)
+ DbgPrintf("H proc %08x tracking hwnd %08x\r\n",
+ GetCurrentProcessId(), hwtty);
+#endif
+ }
+
+ if (*msg == hookwndmsg && *wParam && *lParam == (LPARAM)hwtty && is_tty)
+ {
+ WNDPROC origproc = (WNDPROC)GetWindowLong(hwtty, GWL_WNDPROC);
+ //char myname[MAX_PATH];
+ //if (GetModuleFileName(hmodThis, myname, sizeof(myname)))
+ // hmodLock = LoadLibrary(myname);
+ SetProp(hwtty, origwndprop, origproc);
+ SetWindowLong(hwtty, GWL_WNDPROC, (LONG)WndProc);
+ is_subclassed = TRUE;
+#ifdef DBG
+ DbgPrintf("H proc %08x hwnd:%08x Subclassed\r\n",
+ GetCurrentProcessId(), hwtty);
+#endif
+ if (LOWORD(*wParam) == 2)
+ RegisterWindows9xService(TRUE);
+ }
+
+ 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->wParam, &pmsg->lParam);
+ 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,
+ ...
+ )
+{
+ static HANDLE mutex;
+ va_list marker;
+ TCHAR szBuf[256];
+ DWORD t;
+ HANDLE gDbgOut;
+
+ va_start(marker, fmt);
+ wvsprintf(szBuf, fmt, marker);
+ va_end(marker);
+
+ if (!mutex)
+ mutex = CreateMutex(NULL, FALSE, "Win9xConHookDbgOut");
+ WaitForSingleObject(mutex, INFINITE);
+ gDbgOut = CreateFile("COM1", GENERIC_READ | GENERIC_WRITE, 0,
+ NULL, OPEN_EXISTING, FILE_FLAG_WRITE_THROUGH, NULL);
+ WriteFile(gDbgOut, szBuf, strlen(szBuf), &t, NULL);
+ CloseHandle(gDbgOut);
+ ReleaseMutex(mutex);
+}
+#endif
+
+#endif /* WIN32 */