Release 951124

Tue Nov 21 18:49:10 1995  Alexandre Julliard  <julliard@sunsite.unc.edu>

	* [configure.in] [Makefile] [misc/dos_fs.c]
	Got rid of autoconf.h file.

	* [debugger/dbg.y]
	More logical behavior upon syntax errors.

	* [include/hook.h] [windows/hook.c]
	Changed hook structure and rewrote most of the hook functions for
	better compatibility, based on investigations by Alex Korobka.

	* [include/message.h] [windows/message.c]
	Added hooks to message queue structure and made the structure
	layout Windows-compatible.
	Added support for WH_MOUSE, WH_KEYBOARD, WH_HARDWARE and
	WH_JOURNALRECORD hooks.

	* [misc/main.c]
	Added command-line option for changing the language at run-time
 	(not implemented yet), based on a suggestion from Michael Patra.

	* [objects/cursoricon.c]
	Fixed silly SEGPTR bug in DumpIcon().

Mon Nov 20 22:22:22 1995  Alex Korobka <alex@phm30.pharm.sunysb.edu>

	* [controls/listbox.c] [controls/combo.c] [include/listbox.h]
	Partial implementaion of LBS_EXTENDEDSEL style,
	yet more updates for drag & drop support. Now works.

	* [windows/defwnd.c]
	More message handlers.

	* [windows/win.c]
	DragObject, DragDetect, AnyPopup functions. 

	* [controls/listbox.c]
	More kludgy fixes (WM_...TOITEM, etc.).

	* [objects/cursoricon.c] [objects/oembitmap.c]
	IconToCursor skeleton, patch for OBM_LoadCursorIcon to handle new
	cursor.

	* [include/bitmaps/ocr*]
	New OEM cursors.

Mon Nov 20 11:05:20 EST 1995  Jim Peterson <jspeter@birch.ee.vt.edu>

	* [toolkit/heap.c]
	Swapped flags and size arguments to LocalRealloc as per changes in
	memory/local.c by William Magro in previous release.

	* [include/wintypes.h]
	Reinstated the #define's for 'min' and 'max', since they're part of
	the Windows API.  I really don't think it's a wise idea, so I put
	a '#ifndef DONT_DEFINE_min_AND_max' around them.  I think the actual
	WINE code should never use these (it should use 'MIN' and 'MAX'
	instead).

	* [loader/*]
	Put '#ifndef WINELIB' around many things that WINElib should not need.

	* [controls/edit.c]
	Took out many '#if defined(WINELIB)' sections with the associated
	comment 'temporary fix, until Local memory is correctly implemented in
	WINELIB', since the effective translations are now in 
	toolkit/miscstubs.c.
	Took out the #ifndef's I put in EDIT_ClearText.  Whoever modified this
	file fixed (or at least postponed) the bug I had encountered.

	* [loader/task.c]
	Put an #ifdef in TASK_CreateTask() that hardwires the current drive to
	C:  This will probably cause a lot of trouble if this change is
	forgotten in the future, but it will let things like the OpenFileName
	dialog work for now.

	* [toolkit/libres.c] [toolkit/Makefile.in] [toolkit/Makefile]
	  [include/libres.h]
	Made new libres.c file, which will contain functions for supporting
	accessing resources by name in WINElib.  'winerc' will need to be
	changed.

	* [toolkit/heap.c]
	Refined memory routines to allow for differences between LocalAlloc
	and GlobalAlloc and between LocalSize and GlobalSize.

	* [windows/message.c] [include/windows.h]
	Defined the GetCurrentTime routine in windows/message.c, and removed
	the #define in windows.h.

Mon Nov 20 00:36:42 MET 1995 Sven Verdoolaege <skimo@dns.ufsia.ac.be>

	* [*/*]
	Added new debugging type DEBUG_WIN32 and DEBUG_ENV.

	* [loader/module.c]
	Added undocumented GetExpWinVer.

	* [tools/build.c]
	Previous code didn't pop possibly changed %esi, %edi and %edx
	from the stack.
	
	* [win32/advapi.c]
	Added GetUserNameA.

	* [win32/code_page.c]
	Added stub for MultiByteToWideChar.

	* [win32/console.c]
	Added SetConsoleCtrlHandler stub.

	* [win32/file.c]
	Added ReadFile CreateFileA GetFileInformationByHandle stubs.
	Added CloseHandle.

	* [win32/memory.c]
	Changed VirtualAlloc and VirtualFree.

	* [win32/process.c]
	Added ExitProcess.

Sun Nov 19 17:54:42 1995   Bernd Schmidt <crux@pool.informatik.rwth-aachen.de>

	* [include/windows.h]
	Fixed a few broken structure definitions.

	* [loader/resource.c]
	FindResource(): Need to check for '#xxx' strings here.

	* [miscemu/int21.c]
	FindNext(): Return MS-DOS filenames uppercase.

	* [objects/cursoricon.c]
	CreateIcon(), CreateCursor(): Added missing element to CURSORICONINFO
	initializers.
	
	* [misc/file.c]
	_lopen(): Files opened in OF_WRITE mode are truncated.
	OpenFile(): Ignore OF_READ/OF_WRITE/OF_READWRITE when files are
	created; use read/write mode.
	
	* [misc/profile.c]
	load(): Rewritten.
	
	* [misc/commdlg.c]
	Fixed bad call to strncpy() that smashed the stack.

	* [controls/combo.c] [windows/winpos.c] [memory/selector.c]
	Operator precedence fixes. People who use gcc 2.7.1 don't need a
	debugger :-)
	
	* [if1632/gdi.spec] [objects/palette.c]
	Add ResizePalette() and AnimatePalette() stubs. They don't do anything,
	but sometimes that's good enough.

Fri Nov 17 09:10:35 GMT 1995  John Harvey <john@division.co.uk>

	* [include/wine.h] [include/registers.h] [include/winsock.h]
        Added definitions for Unixware.

	* [loader/signal.c] [misc/comm.c] [misc/winsocket.c]
	Misc. fixes for Unixware.

	* [loader/task.c]
        Made assignemts to context in InitTask for registers use the macros
        from registers.h to make them more portable. (Needed for Unixware)

	* [tools/build.c]
	Fixed register acces routines to work on Unixware. Bit grubby but
 	it seems to work.

	* [controls/edit.c]
	EDIT_WM_NCCreate allocates local heap if hasn't been previously
	allocated.
	
	* [miscemu/int21.c]
	mkdir now creates directory with permission to access it.

	* [misc/dos_fs.c]
	mkdir now creates directory with permission to access it.
	DOS_opendir now uses linked list of dirents to avoid problems with 
	realloc changing address of malloced memory.

Thu Nov 16 12:47:13 1995  Michael Patra  <patra@itp1.Physik.TU-Berlin.DE>

	* [controls/menu.c]
	MENU_CalcItemSize(): Fixed handling of empty menu items.

Sat Nov 11 21:46:54 1995  Hans de Graaff  <graaff@twi72.twi.tudelft.nl>

	* [misc/file.c]
	In OpenFile, unlink should be done on the unix filename.

Sat Nov 11 16:43:29 1995  Cameron Heide  (heide@ee.ualberta.ca)

        * [include/handle32.h]
        New header file containing internal Win32 kernel handle
        information.

        * [win32/file.c]
        Added ReadFile, CreateFile, and CloseFileHandle, and did
        some reorganizing to match the new handle allocation scheme.

        * [win32/init.c]
        Added CloseHandle and the creation of standard I/O handles.

        * [win32/object_mgt.c]
        New module for allocating and freeing Win32 kernel handles.
diff --git a/windows/hook.c b/windows/hook.c
index d56c93f..2460cad 100644
--- a/windows/hook.c
+++ b/windows/hook.c
@@ -1,24 +1,215 @@
 /*
  * Windows hook functions
  *
- * Copyright 1994 Alexandre Julliard
+ * Copyright 1994, 1995 Alexandre Julliard
+ *
+ * Based on investigations by Alex Korobka
  */
 
-/* Warning!
- * HHOOK is not a real handle, but a 32-bit pointer to a HOOKDATA structure.
- * This is for compatibility with Windows 3.0 where HHOOK was a HOOKPROC.
+/*
+ * Warning!
+ * A HHOOK is a 32-bit handle for compatibility with Windows 3.0 where it was
+ * a pointer to the next function. Now it is in fact composed of a USER heap
+ * handle in the low 16 bits and of a HOOK_MAGIC value in the high 16 bits
+ * (except for WINELIB32 where it is a 32-bit handle).  -- AJ
  */
 
 #include "hook.h"
+#include "message.h"
 #include "user.h"
 #include "stddebug.h"
 #include "debug.h"
 
-HHOOK systemHooks[LAST_HOOK-FIRST_HOOK+1] = { 0, };
+  /* This should probably reside in USER heap */
+static HANDLE HOOK_systemHooks[WH_NB_HOOKS] = { 0, };
 
-  /* Task-specific hooks should probably be in the task structure */
-HHOOK taskHooks[LAST_HOOK-FIRST_HOOK+1] = { 0, };
 
+/***********************************************************************
+ *           HOOK_GetNextHook
+ *
+ * Get the next hook of a given hook.
+ */
+static HANDLE HOOK_GetNextHook( HANDLE hook )
+{
+    HOOKDATA *data = (HOOKDATA *)USER_HEAP_LIN_ADDR( hook );
+    if (!data) return 0;
+    if (data->next) return data->next;
+    if (!data->ownerQueue) return 0;  /* Already system hook */
+    /* Now start enumerating the system hooks */
+    return HOOK_systemHooks[data->id - WH_FIRST_HOOK];
+}
+
+
+/***********************************************************************
+ *           HOOK_GetHook
+ *
+ * Get the first hook for a given type.
+ */
+static HANDLE HOOK_GetHook( short id )
+{
+    MESSAGEQUEUE *queue;
+    HANDLE hook = 0;
+
+    if ((queue = (MESSAGEQUEUE *)GlobalLock( GetTaskQueue(0) )) != NULL)
+        hook = queue->hooks[id - WH_FIRST_HOOK];
+    if (!hook) hook = HOOK_systemHooks[id - WH_FIRST_HOOK];
+    return hook;
+}
+
+
+/***********************************************************************
+ *           HOOK_SetHook
+ *
+ * Install a given hook.
+ */
+HANDLE HOOK_SetHook( short id, HOOKPROC proc, HINSTANCE hInst, HTASK hTask )
+{
+    HOOKDATA *data;
+    HANDLE handle;
+    HQUEUE hQueue = 0;
+
+    if ((id < WH_FIRST_HOOK) || (id > WH_LAST_HOOK)) return 0;
+    if (!(hInst = GetExePtr( hInst ))) return 0;
+
+    dprintf_hook( stddeb, "Setting hook %d: %08lx "NPFMT" "NPFMT"\n",
+                  id, (DWORD)proc, hInst, hTask );
+
+    if (hTask)  /* Task-specific hook */
+    {
+	if ((id == WH_JOURNALRECORD) || (id == WH_JOURNALPLAYBACK) ||
+	    (id == WH_SYSMSGFILTER)) return 0;  /* System-only hooks */
+        if (!(hQueue = GetTaskQueue( hTask ))) return 0;
+    }
+
+    if (id == WH_JOURNALPLAYBACK || id == WH_CBT ||
+        id == WH_DEBUG || id == WH_SHELL)
+    {
+	fprintf( stdnimp, "Unimplemented hook set: (%d,%08lx,"NPFMT","NPFMT")!\n",
+                 id, (DWORD)proc, hInst, hTask );
+    }
+
+    /* Create the hook structure */
+
+    if (!(handle = (HANDLE)USER_HEAP_ALLOC( sizeof(HOOKDATA) ))) return 0;
+    data = (HOOKDATA *) USER_HEAP_LIN_ADDR( handle );
+    data->proc        = proc;
+    data->id          = id;
+    data->ownerQueue  = hQueue;
+    data->ownerModule = hInst;
+    data->inHookProc  = 0;
+    dprintf_hook( stddeb, "Setting hook %d: ret="NPFMT"\n", id, handle );
+
+    /* Insert it in the correct linked list */
+
+    if (hQueue)
+    {
+        MESSAGEQUEUE *queue = (MESSAGEQUEUE *)GlobalLock( hQueue );
+        data->next = queue->hooks[id - WH_FIRST_HOOK];
+        queue->hooks[id - WH_FIRST_HOOK] = handle;
+    }
+    else
+    {
+        data->next = HOOK_systemHooks[id - WH_FIRST_HOOK];
+        HOOK_systemHooks[id - WH_FIRST_HOOK] = handle;
+    }
+    return handle;
+}
+
+
+/***********************************************************************
+ *           HOOK_RemoveHook
+ *
+ * Remove a hook from the list.
+ */
+static BOOL HOOK_RemoveHook( HANDLE hook )
+{
+    HOOKDATA *data;
+    HANDLE *prevHook;
+
+    dprintf_hook( stddeb, "Removing hook "NPFMT"\n", hook );
+
+    if (!(data = (HOOKDATA *)USER_HEAP_LIN_ADDR(hook))) return FALSE;
+    if (data->inHookProc)
+    {
+        /* Mark it for deletion later on */
+        dprintf_hook( stddeb, "Hook still running, deletion delayed\n" );
+        data->proc = (FARPROC)0;
+        return TRUE;
+    }
+
+    /* Remove it from the linked list */
+
+    if (data->ownerQueue)
+    {
+        MESSAGEQUEUE *queue = (MESSAGEQUEUE *)GlobalLock( data->ownerQueue );
+        if (!queue) return FALSE;
+        prevHook = &queue->hooks[data->id - WH_FIRST_HOOK];
+    }
+    else prevHook = &HOOK_systemHooks[data->id - WH_FIRST_HOOK];
+
+    while (*prevHook && *prevHook != hook)
+        prevHook = &((HOOKDATA *)USER_HEAP_LIN_ADDR(*prevHook))->next;
+
+     if (!*prevHook) return FALSE;
+    *prevHook = data->next;
+    USER_HEAP_FREE( hook );
+    return TRUE;
+}
+
+
+/***********************************************************************
+ *           HOOK_CallHook
+ *
+ * Call a hook procedure.
+ */
+static DWORD HOOK_CallHook( HANDLE hook, short code,
+                            WPARAM wParam, LPARAM lParam )
+{
+    HOOKDATA *data;
+    MESSAGEQUEUE *queue;
+    HANDLE prevHook;
+    DWORD ret;
+
+    /* Find the first hook with a valid proc */
+
+    for (;;)
+    {
+        if (!hook) return 0;
+        if (!(data = (HOOKDATA *)USER_HEAP_LIN_ADDR(hook))) return 0;
+        if (data->proc) break;
+        hook = data->next;
+    }
+
+    /* Now call it */
+
+    if (!(queue = (MESSAGEQUEUE *)GlobalLock( GetTaskQueue(0) ))) return 0;
+    prevHook = queue->hCurHook;
+    queue->hCurHook = hook;
+    data->inHookProc = 1;
+
+    dprintf_hook( stddeb, "Calling hook "NPFMT": %d %04lx %08lx\n",
+                  hook, code, (DWORD)wParam, lParam );
+    ret = CallHookProc( data->proc, code, wParam, lParam );
+    dprintf_hook( stddeb, "Ret hook "NPFMT" = %08lx\n", hook, ret );
+
+    data->inHookProc = 0;
+    queue->hCurHook = prevHook;
+    if (!data->proc) HOOK_RemoveHook( hook );
+    return ret;
+}
+
+
+/***********************************************************************
+ *           HOOK_CallHooks
+ *
+ * Call a hook chain.
+ */
+DWORD HOOK_CallHooks( short id, short code, WPARAM wParam, LPARAM lParam )
+{
+    HANDLE hook = HOOK_GetHook( id );
+    if (!hook) return 0;
+    return HOOK_CallHook( hook, code, wParam, lParam );
+}
 
 
 /***********************************************************************
@@ -26,55 +217,44 @@
  */
 FARPROC SetWindowsHook( short id, HOOKPROC proc )
 {
-  HHOOK hhook = SetWindowsHookEx( id, proc, 0, 0 );
-  HOOKDATA *data = PTR_SEG_TO_LIN(hhook);
-  if (data != NULL)  {
-    data = PTR_SEG_TO_LIN(data->next);
-    if (data != NULL)  {
-      return data->proc;
-    }
-  }
-  return 0;
+#ifdef WINELIB
+    HINSTANCE hInst = 0;
+#else
+    HINSTANCE hInst = FarGetOwner( HIWORD(proc) );
+#endif
+    /* WH_MSGFILTER is the only task-specific hook for SetWindowsHook() */
+    HTASK hTask = (id == WH_MSGFILTER) ? GetCurrentTask() : 0;
+
+    HANDLE handle = HOOK_SetHook( id, proc, hInst, hTask );
+    if (!handle) return -1;
+    if (!((HOOKDATA *)USER_HEAP_LIN_ADDR( handle ))->next) return 0;
+    /* Not sure if the return value is correct; should not matter much
+     * since it's never used (see DefHookProc). -- AJ */
+#ifdef WINELIB32
+    return (FARPROC)handle;
+#else
+    return (FARPROC)MAKELONG( handle, HOOK_MAGIC );
+#endif
 }
 
 
 /***********************************************************************
  *           UnhookWindowsHook   (USER.234)
  */
-BOOL UnhookWindowsHook( short id, FARPROC hproc )
+BOOL UnhookWindowsHook( short id, HOOKPROC proc )
 {
-  HHOOK *prevHook,hhook;
-  
-  prevHook = &TASK_HOOK(id);
-  while (*prevHook)  {
-    HOOKDATA *data = (HOOKDATA *)PTR_SEG_TO_LIN(*prevHook);
+    HANDLE hook = HOOK_GetHook( id );
 
-    if (data->proc == hproc) {
-      hhook = *prevHook;
-      *prevHook = data->next;
-#ifdef WINELIB32
-      USER_HEAP_FREE((HANDLE)hhook);
-#else
-      USER_HEAP_FREE(LOWORD(hhook));
-#endif
-      return TRUE;
+    dprintf_hook( stddeb, "UnhookWindowsHook: %d %08lx\n", id, (DWORD)proc );
+
+    while (hook)
+    {
+        HOOKDATA *data = (HOOKDATA *)USER_HEAP_LIN_ADDR(hook);
+        if (data->proc == proc) break;
+        hook = HOOK_GetNextHook( hook );
     }
-  }
-  prevHook = &SYSTEM_HOOK(id);
-  while (*prevHook) {
-    HOOKDATA *data = (HOOKDATA *)PTR_SEG_TO_LIN(*prevHook);
-    if (data->proc == hproc) {
-      hhook = *prevHook;
-      *prevHook = data->next;
-#ifdef WINELIB32
-      USER_HEAP_FREE((HANDLE)hhook);
-#else
-      USER_HEAP_FREE(LOWORD(hhook));
-#endif
-      return TRUE;
-    }
-  }
-  return FALSE;
+    if (!hook) return FALSE;
+    return HOOK_RemoveHook( hook );
 }
 
 
@@ -83,7 +263,14 @@
  */
 DWORD DefHookProc( short code, WORD wParam, DWORD lParam, HHOOK *hhook )
 {
-    return CallNextHookEx( *hhook, code, wParam, lParam );
+    /* Note: the *hhook parameter is never used, since we rely on the
+     * current hook value from the task queue to find the next hook. */
+    MESSAGEQUEUE *queue;
+    HANDLE next;
+
+    if (!(queue = (MESSAGEQUEUE *)GlobalLock( GetTaskQueue(0) ))) return 0;
+    if (!(next = HOOK_GetNextHook( queue->hCurHook ))) return 0;
+    return HOOK_CallHook( next, code, wParam, lParam );
 }
 
 
@@ -92,47 +279,23 @@
  */
 BOOL CallMsgFilter( SEGPTR msg, short code )
 {
-    if (CALL_TASK_HOOK( WH_MSGFILTER, code, 0, (LPARAM)msg )) 
-	return TRUE;
-    return CALL_SYSTEM_HOOK( WH_SYSMSGFILTER, code, 0, (LPARAM)msg );
+    if (GetSysModalWindow()) return FALSE;
+    if (HOOK_CallHooks( WH_SYSMSGFILTER, code, 0, (LPARAM)msg )) return TRUE;
+    return HOOK_CallHooks( WH_MSGFILTER, code, 0, (LPARAM)msg );
 }
 
 
 /***********************************************************************
  *           SetWindowsHookEx   (USER.291)
  */
-HHOOK SetWindowsHookEx( short id, HOOKPROC proc, HINSTANCE hinst, HTASK htask )
+HHOOK SetWindowsHookEx( short id, HOOKPROC proc, HINSTANCE hInst, HTASK hTask )
 {
-    HOOKDATA *data;
-    HANDLE handle;
-    HHOOK *prevHook;
-
-    if ((id < FIRST_HOOK) || (id > LAST_HOOK)) return 0;
-    if (id != WH_GETMESSAGE && id != WH_CALLWNDPROC) {
-	fprintf( stdnimp, "Unimplemented hook set: (%d,%08lx,"NPFMT","NPFMT")!\n",
-                 id, (DWORD)proc, hinst, htask );
-    }
-    if (htask)  /* Task-specific hook */
-    {
-	if ((id == WH_JOURNALRECORD) || (id == WH_JOURNALPLAYBACK) ||
-	    (id == WH_SYSMSGFILTER)) return 0;
-	prevHook = &TASK_HOOK( id );
-    }
-    else  /* System-wide hook */
-    {
-	prevHook = &SYSTEM_HOOK( id );
-    }
-    
-    handle = (HANDLE) USER_HEAP_ALLOC( sizeof(*data) );
-    if (!handle) return 0;
-    data   = (HOOKDATA *) USER_HEAP_LIN_ADDR( handle );
-
-    data->next  = *prevHook;
-    data->proc  = proc;
-    data->id    = id;
-    data->htask = htask;
-    *prevHook   = (HHOOK)USER_HEAP_SEG_ADDR(handle);
-    return *prevHook;
+    HANDLE handle = HOOK_SetHook( id, proc, hInst, hTask );
+#ifdef WINELIB32
+    return (HHOOK)handle;
+#else
+    return MAKELONG( handle, HOOK_MAGIC );
+#endif
 }
 
 
@@ -141,22 +304,12 @@
  */
 BOOL UnhookWindowsHookEx( HHOOK hhook )
 {
-    HOOKDATA *data = (HOOKDATA *)PTR_SEG_TO_LIN(hhook);
-    HHOOK *prevHook;
-
-    if (!data) return FALSE;
-    prevHook = data->htask ? &TASK_HOOK(data->id) : &SYSTEM_HOOK(data->id);
-    while (*prevHook && (*prevHook != hhook)) {    
-	prevHook = &((HOOKDATA *)*prevHook)->next;
-    }
-    if (!*prevHook) return FALSE;
-    *prevHook = data->next;
 #ifdef WINELIB32
-    USER_HEAP_FREE( (HANDLE)hhook );
+    return HOOK_RemoveHook( (HANDLE)hhook );
 #else
-    USER_HEAP_FREE( hhook & 0xffff );
+    if (HIWORD(hhook) != HOOK_MAGIC) return FALSE;  /* Not a new format hook */
+    return HOOK_RemoveHook( LOWORD(hhook) );
 #endif
-    return TRUE;
 }
 
 
@@ -165,7 +318,8 @@
  */
 DWORD CallNextHookEx( HHOOK hhook, short code, WPARAM wParam, LPARAM lParam )
 {
-    HOOKDATA *data = (HOOKDATA *)PTR_SEG_TO_LIN(hhook);
-    if (data == NULL || !data->next) return 0;
-    else return INTERNAL_CALL_HOOK( data->next, code, wParam, lParam );
+    HANDLE next;
+    if (HIWORD(hhook) != HOOK_MAGIC) return 0;  /* Not a new format hook */
+    if (!(next = HOOK_GetNextHook( LOWORD(hhook) ))) return 0;
+    return HOOK_CallHook( next, code, wParam, lParam );
 }