Release 970101

Wed Jan  1 15:36:17 1997  Alexandre Julliard  <julliard@lrc.epfl.ch>

	* [controls/listbox.c]
	Use FindFirstFile/FindNextFile in LISTBOX_Directory.

	* [files/dos_fs.c]
	Rewrote FindFirstFile/FindNextFile to use DOSFS_FindNext().

	* [files/file.c] [files/directory.c]
	Use Win32 kernel objects and handles for file handles.
	Unified SearchPath() and OpenFile().

	* [loader/builtin.c]
	Moved to if1632/ directory.

	* [tools/build.c] [debugger/*] [miscemu/*]
	Win16 register functions now receive the same CONTEXT * structure
	as Win32 functions.

	* [include/sigcontext.h] [miscemu/instr.c]
	Added new macros to get register values from the SIGCONTEXT
	structure (only used for instruction emulation now).

	* [scheduler/process.c] [scheduler/thread.c] (New files)
	Allocate process and thread structures.

	* [scheduler/process.c] [win32/k32obj.c]
	Added Win32 kernel objects and handles management.

	* [loader/task.c]
	Create a Win32 process and thread for every Win16 task.

	* [misc/commdlg.c] [misc/shell.c] [windows/msgbox.c]
	Built-in resources are now in Win32 format. This also avoids
	16-bit callbacks for built-in dialogs.

	* [misc/lzexpand.c]
	Differentiate between 16-bit and 32-bit file handles.

	* [miscemu/int*.c]
	Moved all int emulation to msdos/ directory.

	* [msdos/*]
	New directory msdos/ contains all MS-DOS emulation code that can
	also be used for Winelib; this should enable Winelib apps to use
	DOS3Call and related functions.

	* [rc/winerc.c]
	A few bug fixes for Win32 resource format.

	* [windows/winpos.c]
	Hack in WINPOS_ReorderOwnerPopups() to avoid X crashed (still not
	right though).

Sun Dec 29 17:47:55 1996  O. Flebbe <flebbe@science-computing.uni-tuebingen.de>

	* [loader/pe_image.c]
	Make sure BSS of a PE_Image is zero.

Sat Dec 28 22:15:34 1996 Alex Korobka <alex@trantor.pharm.sunysb.edu>

	* [windows/scroll.c]
	ScrollWindowEx() rewrite, ScrollDC() fix.

	* [windows/nonclient.c] [controls/menu.c]
	Fixed Alt-Space crashes in dialogs.

	* [windows/event.c] [windows/message.c]
	Some changes in mouse message generation.

Thu Dec 26 09:25:24 1996  Philippe De Muyter  <phdm@info.ucl.ac.be>

	* [debugger/stabs.c]
	Dummy DEBUG_ReadExecutableDbgInfo provided for !__ELF__ case.

Tue Dec 24 00:59:05 MET 1996  Martin Buck <martin-2.buck@student.uni-ulm.de>

	* [windows/event.c]
	Changed XK_Page_{Up,Down} to XK_{Prior,Next} for X11R5
	compatibility.
diff --git a/scheduler/thread.c b/scheduler/thread.c
new file mode 100644
index 0000000..78b71f8
--- /dev/null
+++ b/scheduler/thread.c
@@ -0,0 +1,231 @@
+/*
+ * Win32 threads
+ *
+ * Copyright 1996 Alexandre Julliard
+ */
+
+#include <assert.h>
+#include "thread.h"
+#include "winerror.h"
+#include "heap.h"
+#include "selectors.h"
+#include "winnt.h"
+
+THDB *pCurrentThread = NULL;
+
+
+/***********************************************************************
+ *           THREAD_Create
+ */
+THDB *THREAD_Create( PDB32 *pdb, DWORD stack_size )
+{
+    THDB *thdb = HeapAlloc( SystemHeap, HEAP_ZERO_MEMORY, sizeof(THDB) );
+    if (!thdb) return NULL;
+    thdb->header.type     = K32OBJ_THREAD;
+    thdb->header.refcount = 1;
+    thdb->process         = pdb;
+    thdb->teb.except      = (void *)-1;
+    thdb->teb.htask16     = 0; /* FIXME */
+    thdb->teb.stack_sel   = 0; /* FIXME */
+    thdb->teb.self        = &thdb->teb;
+    thdb->teb.tls_ptr     = thdb->tls_array;
+    thdb->process2        = pdb;
+    thdb->exit_code       = 0x103; /* STILL_ACTIVE */
+
+    /* Allocate the stack */
+
+    if (!stack_size) stack_size = 1024 * 1024;  /* default size = 1Mb */
+    thdb->stack_base = VirtualAlloc( NULL, stack_size, MEM_COMMIT,
+                                     PAGE_EXECUTE_READWRITE );
+    if (!thdb->stack_base) goto error;
+    /* Un-commit the first page (FIXME: should use PAGE_GUARD instead) */
+    VirtualFree( thdb->stack_base, 1, MEM_DECOMMIT );
+    thdb->teb.stack_top   = (char *)thdb->stack_base + stack_size;
+    thdb->teb.stack_low   = thdb->teb.stack_top;
+    thdb->exit_stack      = thdb->teb.stack_top;
+
+    /* Allocate the TEB selector (%fs register) */
+
+    thdb->teb_sel = SELECTOR_AllocBlock( &thdb->teb, 0x1000, SEGMENT_DATA,
+                                         TRUE, FALSE );
+    if (!thdb->teb_sel) goto error;
+    return thdb;
+
+error:
+    if (thdb->teb_sel) SELECTOR_FreeBlock( thdb->teb_sel, 1 );
+    if (thdb->stack_base) VirtualFree( thdb->stack_base, 0, MEM_RELEASE );
+    HeapFree( SystemHeap, 0, thdb );
+    return NULL;
+}
+
+
+/***********************************************************************
+ *           THREAD_Destroy
+ */
+void THREAD_Destroy( K32OBJ *ptr )
+{
+    THDB *thdb = (THDB *)ptr;
+    assert( ptr->type == K32OBJ_THREAD );
+    ptr->type = K32OBJ_UNKNOWN;
+    SELECTOR_FreeBlock( thdb->teb_sel, 1 );
+    HeapFree( SystemHeap, 0, thdb );
+}
+
+
+/***********************************************************************
+ *           GetCurrentThread   (KERNEL32.200)
+ */
+HANDLE32 GetCurrentThread(void)
+{
+    return 0xFFFFFFFE;
+}
+
+
+/***********************************************************************
+ *           GetCurrentThreadId   (KERNEL32.201)
+ */
+DWORD GetCurrentThreadId(void)
+{
+    /* FIXME: should probably use %fs register here */
+    assert( pCurrentThread );
+    return (DWORD)pCurrentThread;
+}
+
+
+/**********************************************************************
+ *           GetLastError   (KERNEL.148) (KERNEL32.227)
+ */
+DWORD GetLastError(void)
+{
+    THDB *thread = (THDB *)GetCurrentThreadId();
+    return thread->last_error;
+}
+
+
+/**********************************************************************
+ *           SetLastError   (KERNEL.147) (KERNEL32.497)
+ */
+void SetLastError( DWORD error )
+{
+    THDB *thread;
+    if (!pCurrentThread) return;  /* FIXME */
+    thread = (THDB *)GetCurrentThreadId();
+    thread->last_error = error;
+}
+
+
+/**********************************************************************
+ *           SetLastErrorEx   (USER32.484)
+ */
+void SetLastErrorEx( DWORD error, DWORD type )
+{
+    /* FIXME: what about 'type'? */
+    SetLastError( error );
+}
+
+
+/**********************************************************************
+ *           TlsAlloc   (KERNEL32.530)
+ */
+DWORD TlsAlloc(void)
+{
+    DWORD i, mask, ret = 0;
+    THDB *thread = (THDB *)GetCurrentThreadId();
+    DWORD *bits = thread->process->tls_bits;
+    EnterCriticalSection( &thread->process->crit_section );
+    if (*bits == 0xffffffff)
+    {
+        bits++;
+        ret = 32;
+        if (*bits == 0xffffffff)
+        {
+            LeaveCriticalSection( &thread->process->crit_section );
+            SetLastError( ERROR_NO_MORE_ITEMS );
+            return 0xffffffff;
+        }
+    }
+    for (i = 0, mask = 1; i < 32; i++, mask <<= 1) if (!(*bits & mask)) break;
+    *bits |= mask;
+    LeaveCriticalSection( &thread->process->crit_section );
+    return ret + i;
+}
+
+
+/**********************************************************************
+ *           TlsFree   (KERNEL32.531)
+ */
+BOOL32 TlsFree( DWORD index )
+{
+    DWORD mask;
+    THDB *thread = (THDB *)GetCurrentThreadId();
+    DWORD *bits = thread->process->tls_bits;
+    if (index >= 64)
+    {
+        SetLastError( ERROR_INVALID_PARAMETER );
+        return FALSE;
+    }
+    EnterCriticalSection( &thread->process->crit_section );
+    if (index >= 32) bits++;
+    mask = (1 << (index & 31));
+    if (!(*bits & mask))  /* already free? */
+    {
+        LeaveCriticalSection( &thread->process->crit_section );
+        SetLastError( ERROR_INVALID_PARAMETER );
+        return FALSE;
+    }
+    *bits &= ~mask;
+    thread->tls_array[index] = 0;
+    /* FIXME: should zero all other thread values */
+    LeaveCriticalSection( &thread->process->crit_section );
+    return TRUE;
+}
+
+
+/**********************************************************************
+ *           TlsGetValue   (KERNEL32.532)
+ */
+LPVOID TlsGetValue( DWORD index )
+{
+    THDB *thread = (THDB *)GetCurrentThreadId();
+    if (index >= 64)
+    {
+        SetLastError( ERROR_INVALID_PARAMETER );
+        return NULL;
+    }
+    SetLastError( ERROR_SUCCESS );
+    return thread->tls_array[index];
+}
+
+
+/**********************************************************************
+ *           TlsSetValue   (KERNEL32.533)
+ */
+BOOL32 TlsSetValue( DWORD index, LPVOID value )
+{
+    THDB *thread = (THDB *)GetCurrentThreadId();
+    if (index >= 64)
+    {
+        SetLastError( ERROR_INVALID_PARAMETER );
+        return FALSE;
+    }
+    thread->tls_array[index] = value;
+    return TRUE;
+}
+
+
+/***********************************************************************
+ *           GetThreadContext   (KERNEL32.294)
+ */
+BOOL32 GetThreadContext( HANDLE32 handle, CONTEXT *context )
+{
+    return FALSE;
+}
+
+
+/**********************************************************************
+ *           NtCurrentTeb   (NTDLL.89)
+ */
+void NtCurrentTeb( CONTEXT *context )
+{
+    EAX_reg(context) = GetSelectorBase( FS_reg(context) );
+}