From 5fbb446cfc62aa922e893be6fca3915960ae27d7 Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Sat, 23 Aug 2003 00:03:40 +0000 Subject: [PATCH] Moved most of the 16-bit task support and NE module loader to dlls/kernel. --- dlls/kernel/Makefile.in | 3 + dlls/kernel/kernel_main.c | 1 + dlls/kernel/ne_module.c | 1716 +++++++++++++++++ .../ne/segment.c => dlls/kernel/ne_segment.c | 19 +- dlls/kernel/task.c | 1556 +++++++++++++++ dlls/kernel/thunk.c | 4 +- dlls/kernel/wowthunk.c | 4 +- dlls/ntdll/Makefile.in | 3 +- files/drive.c | 10 +- include/task.h | 4 +- include/thread.h | 1 - loader/module.c | 21 - loader/ne/module.c | 1666 ---------------- loader/task.c | 1370 +------------ msdos/int21.c | 2 +- scheduler/thread.c | 35 - 16 files changed, 3301 insertions(+), 3114 deletions(-) create mode 100644 dlls/kernel/ne_module.c rename loader/ne/segment.c => dlls/kernel/ne_segment.c (98%) create mode 100644 dlls/kernel/task.c diff --git a/dlls/kernel/Makefile.in b/dlls/kernel/Makefile.in index 4a8ca0a200a..f5b0e969076 100644 --- a/dlls/kernel/Makefile.in +++ b/dlls/kernel/Makefile.in @@ -34,6 +34,8 @@ C_SRCS = \ lcformat.c \ local16.c \ locale.c \ + ne_module.c \ + ne_segment.c \ powermgnt.c \ process.c \ resource.c \ @@ -42,6 +44,7 @@ C_SRCS = \ string.c \ sync.c \ tape.c \ + task.c \ thread.c \ thunk.c \ time.c \ diff --git a/dlls/kernel/kernel_main.c b/dlls/kernel/kernel_main.c index b01f4d1781e..c756968ecea 100644 --- a/dlls/kernel/kernel_main.c +++ b/dlls/kernel/kernel_main.c @@ -97,6 +97,7 @@ static void thread_detach(void) /* free the 16-bit stack */ K32WOWGlobalFree16( NtCurrentTeb()->stack_sel ); NtCurrentTeb()->cur_stack = 0; + if (!(NtCurrentTeb()->tibflags & TEBF_WIN32)) TASK_ExitTask(); } diff --git a/dlls/kernel/ne_module.c b/dlls/kernel/ne_module.c new file mode 100644 index 00000000000..1a28a42eae6 --- /dev/null +++ b/dlls/kernel/ne_module.c @@ -0,0 +1,1716 @@ +/* + * NE modules + * + * Copyright 1995 Alexandre Julliard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "config.h" +#include "wine/port.h" + +#include +#include +#include +#include +#include +#ifdef HAVE_UNISTD_H +# include +#endif +#include + +#include "winbase.h" +#include "wine/winbase16.h" +#include "winerror.h" +#include "wownt32.h" +#include "wine/library.h" +#include "module.h" +#include "toolhelp.h" +#include "file.h" +#include "task.h" +#include "snoop.h" +#include "builtin16.h" +#include "stackframe.h" +#include "excpt.h" +#include "wine/exception.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(module); +WINE_DECLARE_DEBUG_CHANNEL(loaddll); + +#include "pshpack1.h" +typedef struct _GPHANDLERDEF +{ + WORD selector; + WORD rangeStart; + WORD rangeEnd; + WORD handler; +} GPHANDLERDEF; +#include "poppack.h" + +/* + * Segment table entry + */ +struct ne_segment_table_entry_s +{ + WORD seg_data_offset; /* Sector offset of segment data */ + WORD seg_data_length; /* Length of segment data */ + WORD seg_flags; /* Flags associated with this segment */ + WORD min_alloc; /* Minimum allocation size for this */ +}; + +#define hFirstModule (pThhook->hExeHead) + +static NE_MODULE *pCachedModule = 0; /* Module cached by NE_OpenFile */ + +static HINSTANCE16 NE_LoadModule( LPCSTR name, BOOL lib_only ); +static BOOL16 NE_FreeModule( HMODULE16 hModule, BOOL call_wep ); + +static HINSTANCE16 MODULE_LoadModule16( LPCSTR libname, BOOL implicit, BOOL lib_only ); + +static HMODULE16 NE_GetModuleByFilename( LPCSTR name ); + + +static WINE_EXCEPTION_FILTER(page_fault) +{ + if (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION || + GetExceptionCode() == EXCEPTION_PRIV_INSTRUCTION) + return EXCEPTION_EXECUTE_HANDLER; + return EXCEPTION_CONTINUE_SEARCH; +} + + +/*********************************************************************** + * NE_DumpModule + */ +void NE_DumpModule( HMODULE16 hModule ) +{ + int i, ordinal; + SEGTABLEENTRY *pSeg; + BYTE *pstr; + WORD *pword; + NE_MODULE *pModule; + ET_BUNDLE *bundle; + ET_ENTRY *entry; + + if (!(pModule = NE_GetPtr( hModule ))) + { + MESSAGE( "**** %04x is not a module handle\n", hModule ); + return; + } + + /* Dump the module info */ + DPRINTF( "---\n" ); + DPRINTF( "Module %04x:\n", hModule ); + DPRINTF( "count=%d flags=%04x heap=%d stack=%d\n", + pModule->count, pModule->flags, + pModule->heap_size, pModule->stack_size ); + DPRINTF( "cs:ip=%04x:%04x ss:sp=%04x:%04x ds=%04x nb seg=%d modrefs=%d\n", + pModule->cs, pModule->ip, pModule->ss, pModule->sp, pModule->dgroup, + pModule->seg_count, pModule->modref_count ); + DPRINTF( "os_flags=%d swap_area=%d version=%04x\n", + pModule->os_flags, pModule->min_swap_area, + pModule->expected_version ); + if (pModule->flags & NE_FFLAGS_WIN32) + DPRINTF( "PE module=%p\n", pModule->module32 ); + + /* Dump the file info */ + DPRINTF( "---\n" ); + DPRINTF( "Filename: '%s'\n", NE_MODULE_NAME(pModule) ); + + /* Dump the segment table */ + DPRINTF( "---\n" ); + DPRINTF( "Segment table:\n" ); + pSeg = NE_SEG_TABLE( pModule ); + for (i = 0; i < pModule->seg_count; i++, pSeg++) + DPRINTF( "%02x: pos=%d size=%d flags=%04x minsize=%d hSeg=%04x\n", + i + 1, pSeg->filepos, pSeg->size, pSeg->flags, + pSeg->minsize, pSeg->hSeg ); + + /* Dump the resource table */ + DPRINTF( "---\n" ); + DPRINTF( "Resource table:\n" ); + if (pModule->res_table) + { + pword = (WORD *)((BYTE *)pModule + pModule->res_table); + DPRINTF( "Alignment: %d\n", *pword++ ); + while (*pword) + { + NE_TYPEINFO *ptr = (NE_TYPEINFO *)pword; + NE_NAMEINFO *pname = (NE_NAMEINFO *)(ptr + 1); + DPRINTF( "id=%04x count=%d\n", ptr->type_id, ptr->count ); + for (i = 0; i < ptr->count; i++, pname++) + DPRINTF( "offset=%d len=%d id=%04x\n", + pname->offset, pname->length, pname->id ); + pword = (WORD *)pname; + } + } + else DPRINTF( "None\n" ); + + /* Dump the resident name table */ + DPRINTF( "---\n" ); + DPRINTF( "Resident-name table:\n" ); + pstr = (char *)pModule + pModule->name_table; + while (*pstr) + { + DPRINTF( "%*.*s: %d\n", *pstr, *pstr, pstr + 1, + *(WORD *)(pstr + *pstr + 1) ); + pstr += *pstr + 1 + sizeof(WORD); + } + + /* Dump the module reference table */ + DPRINTF( "---\n" ); + DPRINTF( "Module ref table:\n" ); + if (pModule->modref_table) + { + pword = (WORD *)((BYTE *)pModule + pModule->modref_table); + for (i = 0; i < pModule->modref_count; i++, pword++) + { + char name[10]; + GetModuleName16( *pword, name, sizeof(name) ); + DPRINTF( "%d: %04x -> '%s'\n", i, *pword, name ); + } + } + else DPRINTF( "None\n" ); + + /* Dump the entry table */ + DPRINTF( "---\n" ); + DPRINTF( "Entry table:\n" ); + bundle = (ET_BUNDLE *)((BYTE *)pModule+pModule->entry_table); + do { + entry = (ET_ENTRY *)((BYTE *)bundle+6); + DPRINTF( "Bundle %d-%d: %02x\n", bundle->first, bundle->last, entry->type); + ordinal = bundle->first; + while (ordinal < bundle->last) + { + if (entry->type == 0xff) + DPRINTF("%d: %02x:%04x (moveable)\n", ordinal++, entry->segnum, entry->offs); + else + DPRINTF("%d: %02x:%04x (fixed)\n", ordinal++, entry->segnum, entry->offs); + entry++; + } + } while ( (bundle->next) && (bundle = ((ET_BUNDLE *)((BYTE *)pModule + bundle->next))) ); + + /* Dump the non-resident names table */ + DPRINTF( "---\n" ); + DPRINTF( "Non-resident names table:\n" ); + if (pModule->nrname_handle) + { + pstr = (char *)GlobalLock16( pModule->nrname_handle ); + while (*pstr) + { + DPRINTF( "%*.*s: %d\n", *pstr, *pstr, pstr + 1, + *(WORD *)(pstr + *pstr + 1) ); + pstr += *pstr + 1 + sizeof(WORD); + } + } + DPRINTF( "\n" ); +} + + +/*********************************************************************** + * NE_WalkModules + * + * Walk the module list and print the modules. + */ +void NE_WalkModules(void) +{ + HMODULE16 hModule = hFirstModule; + MESSAGE( "Module Flags Name\n" ); + while (hModule) + { + NE_MODULE *pModule = NE_GetPtr( hModule ); + if (!pModule) + { + MESSAGE( "Bad module %04x in list\n", hModule ); + return; + } + MESSAGE( " %04x %04x %.*s\n", hModule, pModule->flags, + *((char *)pModule + pModule->name_table), + (char *)pModule + pModule->name_table + 1 ); + hModule = pModule->next; + } +} + + +/*********************************************************************** + * EntryAddrProc (KERNEL.667) Wine-specific export + * + * Return the entry point for a given ordinal. + */ +FARPROC16 WINAPI EntryAddrProc16( HMODULE16 hModule, WORD ordinal ) +{ + FARPROC16 ret = NE_GetEntryPointEx( hModule, ordinal, TRUE ); + CURRENT_STACK16->ecx = hModule; /* FIXME: might be incorrect value */ + return ret; +} + +/*********************************************************************** + * NE_SetEntryPoint + * + * Change the value of an entry point. Use with caution! + * It can only change the offset value, not the selector. + */ +BOOL16 NE_SetEntryPoint( HMODULE16 hModule, WORD ordinal, WORD offset ) +{ + NE_MODULE *pModule; + ET_ENTRY *entry; + ET_BUNDLE *bundle; + int i; + + if (!(pModule = NE_GetPtr( hModule ))) return FALSE; + assert( !(pModule->flags & NE_FFLAGS_WIN32) ); + + bundle = (ET_BUNDLE *)((BYTE *)pModule + pModule->entry_table); + while ((ordinal < bundle->first + 1) || (ordinal > bundle->last)) + { + bundle = (ET_BUNDLE *)((BYTE *)pModule + bundle->next); + if (!(bundle->next)) return 0; + } + + entry = (ET_ENTRY *)((BYTE *)bundle+6); + for (i=0; i < (ordinal - bundle->first - 1); i++) + entry++; + + memcpy( &entry->offs, &offset, sizeof(WORD) ); + return TRUE; +} + + +/*********************************************************************** + * NE_OpenFile + */ +HANDLE NE_OpenFile( NE_MODULE *pModule ) +{ + HANDLE handle; + char *name; + + TRACE("(%p)\n", pModule ); + /* mjm - removed module caching because it keeps open file handles + thus preventing CDROMs from being ejected */ + name = NE_MODULE_NAME( pModule ); + if ((handle = CreateFileA( name, GENERIC_READ, FILE_SHARE_READ, + NULL, OPEN_EXISTING, 0, 0 )) == INVALID_HANDLE_VALUE) + MESSAGE( "Can't open file '%s' for module %04x\n", name, pModule->self ); + TRACE("opened '%s' -> %p\n", name, handle); + return handle; +} + + +/* wrapper for SetFilePointer and ReadFile */ +static BOOL read_data( HANDLE handle, LONG offset, void *buffer, DWORD size ) +{ + DWORD result; + + if (SetFilePointer( handle, offset, NULL, SEEK_SET ) == INVALID_SET_FILE_POINTER) return FALSE; + if (!ReadFile( handle, buffer, size, &result, NULL )) return FALSE; + return (result == size); +} + +/*********************************************************************** + * NE_LoadExeHeader + */ +static HMODULE16 NE_LoadExeHeader( HANDLE handle, LPCSTR path ) +{ + IMAGE_DOS_HEADER mz_header; + IMAGE_OS2_HEADER ne_header; + int size; + HMODULE16 hModule; + NE_MODULE *pModule; + BYTE *pData, *pTempEntryTable; + char *buffer, *fastload = NULL; + int fastload_offset = 0, fastload_length = 0; + ET_ENTRY *entry; + ET_BUNDLE *bundle, *oldbundle; + OFSTRUCT *ofs; + + /* Read a block from either the file or the fast-load area. */ +#define READ(offset,size,buffer) \ + ((fastload && ((offset) >= fastload_offset) && \ + ((offset)+(size) <= fastload_offset+fastload_length)) ? \ + (memcpy( buffer, fastload+(offset)-fastload_offset, (size) ), TRUE) : \ + read_data( handle, (offset), (buffer), (size))) + + if (!read_data( handle, 0, &mz_header, sizeof(mz_header)) || + (mz_header.e_magic != IMAGE_DOS_SIGNATURE)) + return (HMODULE16)11; /* invalid exe */ + + if (!read_data( handle, mz_header.e_lfanew, &ne_header, sizeof(ne_header) )) + return (HMODULE16)11; /* invalid exe */ + + if (ne_header.ne_magic == IMAGE_NT_SIGNATURE) return (HMODULE16)21; /* win32 exe */ + if (ne_header.ne_magic == IMAGE_OS2_SIGNATURE_LX) { + MESSAGE("Sorry, this is an OS/2 linear executable (LX) file !\n"); + return (HMODULE16)12; + } + if (ne_header.ne_magic != IMAGE_OS2_SIGNATURE) return (HMODULE16)11; /* invalid exe */ + + /* We now have a valid NE header */ + + size = sizeof(NE_MODULE) + + /* segment table */ + ne_header.ne_cseg * sizeof(SEGTABLEENTRY) + + /* resource table */ + ne_header.ne_restab - ne_header.ne_rsrctab + + /* resident names table */ + ne_header.ne_modtab - ne_header.ne_restab + + /* module ref table */ + ne_header.ne_cmod * sizeof(WORD) + + /* imported names table */ + ne_header.ne_enttab - ne_header.ne_imptab + + /* entry table length */ + ne_header.ne_cbenttab + + /* entry table extra conversion space */ + sizeof(ET_BUNDLE) + + 2 * (ne_header.ne_cbenttab - ne_header.ne_cmovent*6) + + /* loaded file info */ + sizeof(OFSTRUCT) - sizeof(ofs->szPathName) + strlen(path) + 1; + + hModule = GlobalAlloc16( GMEM_FIXED | GMEM_ZEROINIT, size ); + if (!hModule) return (HMODULE16)11; /* invalid exe */ + + FarSetOwner16( hModule, hModule ); + pModule = (NE_MODULE *)GlobalLock16( hModule ); + memcpy( pModule, &ne_header, sizeof(ne_header) ); + pModule->count = 0; + /* check *programs* for default minimal stack size */ + if ( (!(pModule->flags & NE_FFLAGS_LIBMODULE)) + && (pModule->stack_size < 0x1400) ) + pModule->stack_size = 0x1400; + pModule->module32 = 0; + pModule->self = hModule; + pModule->self_loading_sel = 0; + pData = (BYTE *)(pModule + 1); + + /* Clear internal Wine flags in case they are set in the EXE file */ + + pModule->flags &= ~(NE_FFLAGS_BUILTIN | NE_FFLAGS_WIN32); + + /* Read the fast-load area */ + + if (ne_header.ne_flagsothers & NE_AFLAGS_FASTLOAD) + { + fastload_offset=ne_header.ne_pretthunks << ne_header.ne_align; + fastload_length=ne_header.ne_psegrefbytes << ne_header.ne_align; + TRACE("Using fast-load area offset=%x len=%d\n", + fastload_offset, fastload_length ); + if ((fastload = HeapAlloc( GetProcessHeap(), 0, fastload_length )) != NULL) + { + if (!read_data( handle, fastload_offset, fastload, fastload_length)) + { + HeapFree( GetProcessHeap(), 0, fastload ); + WARN("Error reading fast-load area!\n"); + fastload = NULL; + } + } + } + + /* Get the segment table */ + + pModule->seg_table = pData - (BYTE *)pModule; + buffer = HeapAlloc( GetProcessHeap(), 0, ne_header.ne_cseg * + sizeof(struct ne_segment_table_entry_s)); + if (buffer) + { + int i; + struct ne_segment_table_entry_s *pSeg; + + if (!READ( mz_header.e_lfanew + ne_header.ne_segtab, + ne_header.ne_cseg * sizeof(struct ne_segment_table_entry_s), + buffer )) + { + HeapFree( GetProcessHeap(), 0, buffer ); + if (fastload) HeapFree( GetProcessHeap(), 0, fastload ); + GlobalFree16( hModule ); + return (HMODULE16)11; /* invalid exe */ + } + pSeg = (struct ne_segment_table_entry_s *)buffer; + for (i = ne_header.ne_cseg; i > 0; i--, pSeg++) + { + memcpy( pData, pSeg, sizeof(*pSeg) ); + pData += sizeof(SEGTABLEENTRY); + } + HeapFree( GetProcessHeap(), 0, buffer ); + } + else + { + if (fastload) HeapFree( GetProcessHeap(), 0, fastload ); + GlobalFree16( hModule ); + return (HMODULE16)11; /* invalid exe */ + } + + /* Get the resource table */ + + if (ne_header.ne_rsrctab < ne_header.ne_restab) + { + pModule->res_table = pData - (BYTE *)pModule; + if (!READ(mz_header.e_lfanew + ne_header.ne_rsrctab, + ne_header.ne_restab - ne_header.ne_rsrctab, + pData )) + return (HMODULE16)11; /* invalid exe */ + pData += ne_header.ne_restab - ne_header.ne_rsrctab; + NE_InitResourceHandler( pModule ); + } + else pModule->res_table = 0; /* No resource table */ + + /* Get the resident names table */ + + pModule->name_table = pData - (BYTE *)pModule; + if (!READ( mz_header.e_lfanew + ne_header.ne_restab, + ne_header.ne_modtab - ne_header.ne_restab, + pData )) + { + if (fastload) HeapFree( GetProcessHeap(), 0, fastload ); + GlobalFree16( hModule ); + return (HMODULE16)11; /* invalid exe */ + } + pData += ne_header.ne_modtab - ne_header.ne_restab; + + /* Get the module references table */ + + if (ne_header.ne_cmod > 0) + { + pModule->modref_table = pData - (BYTE *)pModule; + if (!READ( mz_header.e_lfanew + ne_header.ne_modtab, + ne_header.ne_cmod * sizeof(WORD), + pData )) + { + if (fastload) HeapFree( GetProcessHeap(), 0, fastload ); + GlobalFree16( hModule ); + return (HMODULE16)11; /* invalid exe */ + } + pData += ne_header.ne_cmod * sizeof(WORD); + } + else pModule->modref_table = 0; /* No module references */ + + /* Get the imported names table */ + + pModule->import_table = pData - (BYTE *)pModule; + if (!READ( mz_header.e_lfanew + ne_header.ne_imptab, + ne_header.ne_enttab - ne_header.ne_imptab, + pData )) + { + if (fastload) HeapFree( GetProcessHeap(), 0, fastload ); + GlobalFree16( hModule ); + return (HMODULE16)11; /* invalid exe */ + } + pData += ne_header.ne_enttab - ne_header.ne_imptab; + + /* Load entry table, convert it to the optimized version used by Windows */ + + if ((pTempEntryTable = HeapAlloc( GetProcessHeap(), 0, ne_header.ne_cbenttab)) != NULL) + { + BYTE nr_entries, type, *s; + + TRACE("Converting entry table.\n"); + pModule->entry_table = pData - (BYTE *)pModule; + if (!READ( mz_header.e_lfanew + ne_header.ne_enttab, + ne_header.ne_cbenttab, pTempEntryTable )) + { + HeapFree( GetProcessHeap(), 0, pTempEntryTable ); + if (fastload) HeapFree( GetProcessHeap(), 0, fastload ); + GlobalFree16( hModule ); + return (HMODULE16)11; /* invalid exe */ + } + + s = pTempEntryTable; + TRACE("entry table: offs %04x, len %04x, entries %d\n", ne_header.ne_enttab, ne_header.ne_cbenttab, *s); + + bundle = (ET_BUNDLE *)pData; + TRACE("first bundle: %p\n", bundle); + memset(bundle, 0, sizeof(ET_BUNDLE)); /* in case no entry table exists */ + entry = (ET_ENTRY *)((BYTE *)bundle+6); + + while ((nr_entries = *s++)) + { + if ((type = *s++)) + { + bundle->last += nr_entries; + if (type == 0xff) + while (nr_entries--) + { + entry->type = type; + entry->flags = *s++; + s += 2; + entry->segnum = *s++; + entry->offs = *(WORD *)s; s += 2; + /*TRACE(module, "entry: %p, type: %d, flags: %d, segnum: %d, offs: %04x\n", entry, entry->type, entry->flags, entry->segnum, entry->offs);*/ + entry++; + } + else + while (nr_entries--) + { + entry->type = type; + entry->flags = *s++; + entry->segnum = type; + entry->offs = *(WORD *)s; s += 2; + /*TRACE(module, "entry: %p, type: %d, flags: %d, segnum: %d, offs: %04x\n", entry, entry->type, entry->flags, entry->segnum, entry->offs);*/ + entry++; + } + } + else + { + if (bundle->first == bundle->last) + { + bundle->first += nr_entries; + bundle->last += nr_entries; + } + else + { + oldbundle = bundle; + oldbundle->next = ((int)entry - (int)pModule); + bundle = (ET_BUNDLE *)entry; + TRACE("new bundle: %p\n", bundle); + bundle->first = bundle->last = + oldbundle->last + nr_entries; + bundle->next = 0; + (BYTE *)entry += sizeof(ET_BUNDLE); + } + } + } + HeapFree( GetProcessHeap(), 0, pTempEntryTable ); + } + else + { + if (fastload) HeapFree( GetProcessHeap(), 0, fastload ); + GlobalFree16( hModule ); + return (HMODULE16)11; /* invalid exe */ + } + + pData += ne_header.ne_cbenttab + sizeof(ET_BUNDLE) + + 2 * (ne_header.ne_cbenttab - ne_header.ne_cmovent*6); + + if ((DWORD)entry > (DWORD)pData) + ERR("converted entry table bigger than reserved space !!!\nentry: %p, pData: %p. Please report !\n", entry, pData); + + /* Store the filename information */ + + pModule->fileinfo = pData - (BYTE *)pModule; + size = sizeof(OFSTRUCT) - sizeof(ofs->szPathName) + strlen(path) + 1; + ofs = (OFSTRUCT *)pData; + ofs->cBytes = size - 1; + ofs->fFixedDisk = 1; + strcpy( ofs->szPathName, path ); + pData += size; + + /* Free the fast-load area */ + +#undef READ + if (fastload) HeapFree( GetProcessHeap(), 0, fastload ); + + /* Get the non-resident names table */ + + if (ne_header.ne_cbnrestab) + { + pModule->nrname_handle = GlobalAlloc16( 0, ne_header.ne_cbnrestab ); + if (!pModule->nrname_handle) + { + GlobalFree16( hModule ); + return (HMODULE16)11; /* invalid exe */ + } + FarSetOwner16( pModule->nrname_handle, hModule ); + buffer = GlobalLock16( pModule->nrname_handle ); + if (!read_data( handle, ne_header.ne_nrestab, buffer, ne_header.ne_cbnrestab )) + { + GlobalFree16( pModule->nrname_handle ); + GlobalFree16( hModule ); + return (HMODULE16)11; /* invalid exe */ + } + } + else pModule->nrname_handle = 0; + + /* Allocate a segment for the implicitly-loaded DLLs */ + + if (pModule->modref_count) + { + pModule->dlls_to_init = GlobalAlloc16( GMEM_ZEROINIT, + (pModule->modref_count+1)*sizeof(HMODULE16) ); + if (!pModule->dlls_to_init) + { + if (pModule->nrname_handle) GlobalFree16( pModule->nrname_handle ); + GlobalFree16( hModule ); + return (HMODULE16)11; /* invalid exe */ + } + FarSetOwner16( pModule->dlls_to_init, hModule ); + } + else pModule->dlls_to_init = 0; + + NE_RegisterModule( pModule ); + SNOOP16_RegisterDLL(pModule,path); + return hModule; +} + + +/*********************************************************************** + * NE_LoadDLLs + * + * Load all DLLs implicitly linked to a module. + */ +static BOOL NE_LoadDLLs( NE_MODULE *pModule ) +{ + int i; + WORD *pModRef = (WORD *)((char *)pModule + pModule->modref_table); + WORD *pDLLs = (WORD *)GlobalLock16( pModule->dlls_to_init ); + + for (i = 0; i < pModule->modref_count; i++, pModRef++) + { + char buffer[260], *p; + BYTE *pstr = (BYTE *)pModule + pModule->import_table + *pModRef; + memcpy( buffer, pstr + 1, *pstr ); + *(buffer + *pstr) = 0; /* terminate it */ + + TRACE("Loading '%s'\n", buffer ); + if (!(*pModRef = GetModuleHandle16( buffer ))) + { + /* If the DLL is not loaded yet, load it and store */ + /* its handle in the list of DLLs to initialize. */ + HMODULE16 hDLL; + + /* Append .DLL to name if no extension present */ + if (!(p = strrchr( buffer, '.')) || strchr( p, '/' ) || strchr( p, '\\')) + strcat( buffer, ".DLL" ); + + if ((hDLL = MODULE_LoadModule16( buffer, TRUE, TRUE )) < 32) + { + /* FIXME: cleanup what was done */ + + MESSAGE( "Could not load '%s' required by '%.*s', error=%d\n", + buffer, *((BYTE*)pModule + pModule->name_table), + (char *)pModule + pModule->name_table + 1, hDLL ); + return FALSE; + } + *pModRef = GetExePtr( hDLL ); + *pDLLs++ = *pModRef; + } + else /* Increment the reference count of the DLL */ + { + NE_MODULE *pOldDLL = NE_GetPtr( *pModRef ); + if (pOldDLL) pOldDLL->count++; + } + } + return TRUE; +} + + +/********************************************************************** + * NE_DoLoadModule + * + * Load first instance of NE module from file. + * + * pModule must point to a module structure prepared by NE_LoadExeHeader. + * This routine must never be called twice on a module. + * + */ +static HINSTANCE16 NE_DoLoadModule( NE_MODULE *pModule ) +{ + /* Allocate the segments for this module */ + + if (!NE_CreateAllSegments( pModule )) + return ERROR_NOT_ENOUGH_MEMORY; /* 8 */ + + /* Load the referenced DLLs */ + + if (!NE_LoadDLLs( pModule )) + return ERROR_FILE_NOT_FOUND; /* 2 */ + + /* Load the segments */ + + NE_LoadAllSegments( pModule ); + + /* Make sure the usage count is 1 on the first loading of */ + /* the module, even if it contains circular DLL references */ + + pModule->count = 1; + + return NE_GetInstance( pModule ); +} + +/********************************************************************** + * NE_LoadModule + * + * Load first instance of NE module. (Note: caller is responsible for + * ensuring the module isn't already loaded!) + * + * If the module turns out to be an executable module, only a + * handle to a module stub is returned; this needs to be initialized + * by calling NE_DoLoadModule later, in the context of the newly + * created process. + * + * If lib_only is TRUE, however, the module is perforce treated + * like a DLL module, even if it is an executable module. + * + */ +static HINSTANCE16 NE_LoadModule( LPCSTR name, BOOL lib_only ) +{ + NE_MODULE *pModule; + HMODULE16 hModule; + HINSTANCE16 hInstance; + HFILE16 hFile; + OFSTRUCT ofs; + + /* Open file */ + if ((hFile = OpenFile16( name, &ofs, OF_READ )) == HFILE_ERROR16) + return (HMODULE16)2; /* File not found */ + + hModule = NE_LoadExeHeader( DosFileHandleToWin32Handle(hFile), ofs.szPathName ); + _lclose16( hFile ); + if (hModule < 32) return hModule; + + pModule = NE_GetPtr( hModule ); + if ( !pModule ) return hModule; + + if ( !lib_only && !( pModule->flags & NE_FFLAGS_LIBMODULE ) ) + return hModule; + + hInstance = NE_DoLoadModule( pModule ); + if ( hInstance < 32 ) + { + /* cleanup ... */ + NE_FreeModule( hModule, 0 ); + } + + return hInstance; +} + + +/********************************************************************** + * MODULE_LoadModule16 + * + * Load a NE module in the order of the loadorder specification. + * The caller is responsible that the module is not loaded already. + * + */ +static HINSTANCE16 MODULE_LoadModule16( LPCSTR libname, BOOL implicit, BOOL lib_only ) +{ + HINSTANCE16 hinst = 2; + enum loadorder_type loadorder[LOADORDER_NTYPES]; + int i; + const char *filetype = ""; + + MODULE_GetLoadOrder(loadorder, libname, FALSE); + + for(i = 0; i < LOADORDER_NTYPES; i++) + { + if (loadorder[i] == LOADORDER_INVALID) break; + + switch(loadorder[i]) + { + case LOADORDER_DLL: + TRACE("Trying native dll '%s'\n", libname); + hinst = NE_LoadModule(libname, lib_only); + filetype = "native"; + break; + + case LOADORDER_BI: + TRACE("Trying built-in '%s'\n", libname); + hinst = BUILTIN_LoadModule(libname); + filetype = "builtin"; + break; + + default: + hinst = 2; + break; + } + + if(hinst >= 32) + { + TRACE_(loaddll)("Loaded module '%s' : %s\n", libname, filetype); + if(!implicit) + { + HMODULE16 hModule; + NE_MODULE *pModule; + + hModule = GetModuleHandle16(libname); + if(!hModule) + { + ERR("Serious trouble. Just loaded module '%s' (hinst=0x%04x), but can't get module handle. Filename too long ?\n", + libname, hinst); + return 6; /* ERROR_INVALID_HANDLE seems most appropriate */ + } + + pModule = NE_GetPtr(hModule); + if(!pModule) + { + ERR("Serious trouble. Just loaded module '%s' (hinst=0x%04x), but can't get NE_MODULE pointer\n", + libname, hinst); + return 6; /* ERROR_INVALID_HANDLE seems most appropriate */ + } + + TRACE("Loaded module '%s' at 0x%04x.\n", libname, hinst); + + /* + * Call initialization routines for all loaded DLLs. Note that + * when we load implicitly linked DLLs this will be done by InitTask(). + */ + if(pModule->flags & NE_FFLAGS_LIBMODULE) + { + NE_InitializeDLLs(hModule); + NE_DllProcessAttach(hModule); + } + } + return hinst; + } + + if(hinst != 2) + { + /* We quit searching when we get another error than 'File not found' */ + break; + } + } + return hinst; /* The last error that occurred */ +} + + +/********************************************************************** + * NE_CreateThread + * + * Create the thread for a 16-bit module. + */ +static HINSTANCE16 NE_CreateThread( NE_MODULE *pModule, WORD cmdShow, LPCSTR cmdline ) +{ + HANDLE hThread; + TDB *pTask; + HTASK16 hTask; + HINSTANCE16 instance = 0; + + if (!(hTask = TASK_SpawnTask( pModule, cmdShow, cmdline + 1, *cmdline, &hThread ))) + return 0; + + /* Post event to start the task */ + PostEvent16( hTask ); + + /* Wait until we get the instance handle */ + do + { + DirectedYield16( hTask ); + if (!IsTask16( hTask )) /* thread has died */ + { + DWORD exit_code; + WaitForSingleObject( hThread, INFINITE ); + GetExitCodeThread( hThread, &exit_code ); + CloseHandle( hThread ); + return exit_code; + } + if (!(pTask = GlobalLock16( hTask ))) break; + instance = pTask->hInstance; + GlobalUnlock16( hTask ); + } while (!instance); + + CloseHandle( hThread ); + return instance; +} + + +/********************************************************************** + * LoadModule (KERNEL.45) + */ +HINSTANCE16 WINAPI LoadModule16( LPCSTR name, LPVOID paramBlock ) +{ + BOOL lib_only = !paramBlock || (paramBlock == (LPVOID)-1); + LOADPARAMS16 *params; + HMODULE16 hModule; + NE_MODULE *pModule; + LPSTR cmdline; + WORD cmdShow; + + /* Load module */ + + if ( (hModule = NE_GetModuleByFilename(name) ) != 0 ) + { + /* Special case: second instance of an already loaded NE module */ + + if ( !( pModule = NE_GetPtr( hModule ) ) ) return (HINSTANCE16)11; + if ( pModule->module32 ) return (HINSTANCE16)21; + + /* Increment refcount */ + + pModule->count++; + } + else + { + /* Main case: load first instance of NE module */ + + if ( (hModule = MODULE_LoadModule16( name, FALSE, lib_only )) < 32 ) + return hModule; + + if ( !(pModule = NE_GetPtr( hModule )) ) + return (HINSTANCE16)11; + } + + /* If library module, we just retrieve the instance handle */ + + if ( ( pModule->flags & NE_FFLAGS_LIBMODULE ) || lib_only ) + return NE_GetInstance( pModule ); + + /* + * At this point, we need to create a new process. + * + * pModule points either to an already loaded module, whose refcount + * has already been incremented (to avoid having the module vanish + * in the meantime), or else to a stub module which contains only header + * information. + */ + params = (LOADPARAMS16 *)paramBlock; + cmdShow = ((WORD *)MapSL(params->showCmd))[1]; + cmdline = MapSL( params->cmdLine ); + return NE_CreateThread( pModule, cmdShow, cmdline ); +} + + +/********************************************************************** + * NE_StartTask + * + * Startup code for a new 16-bit task. + */ +DWORD NE_StartTask(void) +{ + TDB *pTask = TASK_GetCurrent(); + NE_MODULE *pModule = NE_GetPtr( pTask->hModule ); + HINSTANCE16 hInstance, hPrevInstance; + SEGTABLEENTRY *pSegTable = NE_SEG_TABLE( pModule ); + WORD sp; + + if ( pModule->count > 0 ) + { + /* Second instance of an already loaded NE module */ + /* Note that the refcount was already incremented by the parent */ + + hPrevInstance = NE_GetInstance( pModule ); + + if ( pModule->dgroup ) + if ( NE_CreateSegment( pModule, pModule->dgroup ) ) + NE_LoadSegment( pModule, pModule->dgroup ); + + hInstance = NE_GetInstance( pModule ); + TRACE("created second instance %04x[%d] of instance %04x.\n", hInstance, pModule->dgroup, hPrevInstance); + + } + else + { + /* Load first instance of NE module */ + + pModule->flags |= NE_FFLAGS_GUI; /* FIXME: is this necessary? */ + + hInstance = NE_DoLoadModule( pModule ); + hPrevInstance = 0; + } + + if ( hInstance >= 32 ) + { + CONTEXT86 context; + + /* Enter instance handles into task struct */ + + pTask->hInstance = hInstance; + pTask->hPrevInstance = hPrevInstance; + + /* Use DGROUP for 16-bit stack */ + + if (!(sp = pModule->sp)) + sp = pSegTable[pModule->ss-1].minsize + pModule->stack_size; + sp &= ~1; + sp -= sizeof(STACK16FRAME); + pTask->teb->cur_stack = MAKESEGPTR( GlobalHandleToSel16(hInstance), sp ); + + /* Registers at initialization must be: + * ax zero + * bx stack size in bytes + * cx heap size in bytes + * si previous app instance + * di current app instance + * bp zero + * es selector to the PSP + * ds dgroup of the application + * ss stack selector + * sp top of the stack + */ + memset( &context, 0, sizeof(context) ); + context.SegCs = GlobalHandleToSel16(pSegTable[pModule->cs - 1].hSeg); + context.SegDs = GlobalHandleToSel16(pTask->hInstance); + context.SegEs = pTask->hPDB; + context.Eip = pModule->ip; + context.Ebx = pModule->stack_size; + context.Ecx = pModule->heap_size; + context.Edi = pTask->hInstance; + context.Esi = pTask->hPrevInstance; + + /* Now call 16-bit entry point */ + + TRACE("Starting main program: cs:ip=%04lx:%04lx ds=%04lx ss:sp=%04x:%04x\n", + context.SegCs, context.Eip, context.SegDs, + SELECTOROF(pTask->teb->cur_stack), + OFFSETOF(pTask->teb->cur_stack) ); + + wine_call_to_16_regs_short( &context, 0 ); + ExitThread( LOWORD(context.Eax) ); + } + return hInstance; /* error code */ +} + +/*********************************************************************** + * LoadLibrary (KERNEL.95) + * LoadLibrary16 (KERNEL32.35) + */ +HINSTANCE16 WINAPI LoadLibrary16( LPCSTR libname ) +{ + return LoadModule16(libname, (LPVOID)-1 ); +} + + +/********************************************************************** + * MODULE_CallWEP + * + * Call a DLL's WEP, allowing it to shut down. + * FIXME: we always pass the WEP WEP_FREE_DLL, never WEP_SYSTEM_EXIT + */ +static BOOL16 MODULE_CallWEP( HMODULE16 hModule ) +{ + BOOL16 ret; + FARPROC16 WEP = GetProcAddress16( hModule, "WEP" ); + if (!WEP) return FALSE; + + __TRY + { + WORD args[1]; + DWORD dwRet; + + args[0] = WEP_FREE_DLL; + WOWCallback16Ex( (DWORD)WEP, WCB16_PASCAL, sizeof(args), args, &dwRet ); + ret = LOWORD(dwRet); + } + __EXCEPT(page_fault) + { + WARN("Page fault\n"); + ret = 0; + } + __ENDTRY + + return ret; +} + + +/********************************************************************** + * NE_FreeModule + * + * Implementation of FreeModule16(). + */ +static BOOL16 NE_FreeModule( HMODULE16 hModule, BOOL call_wep ) +{ + HMODULE16 *hPrevModule; + NE_MODULE *pModule; + HMODULE16 *pModRef; + int i; + + if (!(pModule = NE_GetPtr( hModule ))) return FALSE; + hModule = pModule->self; + + TRACE("%04x count %d\n", hModule, pModule->count ); + + if (((INT16)(--pModule->count)) > 0 ) return TRUE; + else pModule->count = 0; + + if (pModule->flags & NE_FFLAGS_BUILTIN) + return FALSE; /* Can't free built-in module */ + + if (call_wep && !(pModule->flags & NE_FFLAGS_WIN32)) + { + /* Free the objects owned by the DLL module */ + NE_CallUserSignalProc( hModule, USIG16_DLL_UNLOAD ); + + if (pModule->flags & NE_FFLAGS_LIBMODULE) + MODULE_CallWEP( hModule ); + else + call_wep = FALSE; /* We are freeing a task -> no more WEPs */ + } + + + /* Clear magic number just in case */ + + pModule->magic = pModule->self = 0; + + /* Remove it from the linked list */ + + hPrevModule = &hFirstModule; + while (*hPrevModule && (*hPrevModule != hModule)) + { + hPrevModule = &(NE_GetPtr( *hPrevModule ))->next; + } + if (*hPrevModule) *hPrevModule = pModule->next; + + /* Free the referenced modules */ + + pModRef = (HMODULE16*)NE_MODULE_TABLE( pModule ); + for (i = 0; i < pModule->modref_count; i++, pModRef++) + { + NE_FreeModule( *pModRef, call_wep ); + } + + /* Free the module storage */ + + GlobalFreeAll16( hModule ); + + /* Remove module from cache */ + + if (pCachedModule == pModule) pCachedModule = NULL; + return TRUE; +} + + +/********************************************************************** + * FreeModule (KERNEL.46) + */ +BOOL16 WINAPI FreeModule16( HMODULE16 hModule ) +{ + return NE_FreeModule( hModule, TRUE ); +} + + +/*********************************************************************** + * FreeLibrary (KERNEL.96) + * FreeLibrary16 (KERNEL32.36) + */ +void WINAPI FreeLibrary16( HINSTANCE16 handle ) +{ + TRACE("%04x\n", handle ); + FreeModule16( handle ); +} + + +/********************************************************************** + * GetModuleName (KERNEL.27) + */ +BOOL16 WINAPI GetModuleName16( HINSTANCE16 hinst, LPSTR buf, INT16 count ) +{ + NE_MODULE *pModule; + BYTE *p; + + if (!(pModule = NE_GetPtr( hinst ))) return FALSE; + p = (BYTE *)pModule + pModule->name_table; + if (count > *p) count = *p + 1; + if (count > 0) + { + memcpy( buf, p + 1, count - 1 ); + buf[count-1] = '\0'; + } + return TRUE; +} + + +/********************************************************************** + * GetModuleUsage (KERNEL.48) + */ +INT16 WINAPI GetModuleUsage16( HINSTANCE16 hModule ) +{ + NE_MODULE *pModule = NE_GetPtr( hModule ); + return pModule ? pModule->count : 0; +} + + +/********************************************************************** + * GetExpWinVer (KERNEL.167) + */ +WORD WINAPI GetExpWinVer16( HMODULE16 hModule ) +{ + NE_MODULE *pModule = NE_GetPtr( hModule ); + if ( !pModule ) return 0; + + /* + * For built-in modules, fake the expected version the module should + * have according to the Windows version emulated by Wine + */ + if ( !pModule->expected_version ) + { + OSVERSIONINFOA versionInfo; + versionInfo.dwOSVersionInfoSize = sizeof(versionInfo); + + if ( GetVersionExA( &versionInfo ) ) + pModule->expected_version = + (versionInfo.dwMajorVersion & 0xff) << 8 + | (versionInfo.dwMinorVersion & 0xff); + } + + return pModule->expected_version; +} + + +/*********************************************************************** + * WinExec (KERNEL.166) + */ +HINSTANCE16 WINAPI WinExec16( LPCSTR lpCmdLine, UINT16 nCmdShow ) +{ + LPCSTR p, args = NULL; + LPCSTR name_beg, name_end; + LPSTR name, cmdline; + int arglen; + HINSTANCE16 ret; + char buffer[MAX_PATH]; + + if (*lpCmdLine == '"') /* has to be only one and only at beginning ! */ + { + name_beg = lpCmdLine+1; + p = strchr ( lpCmdLine+1, '"' ); + if (p) + { + name_end = p; + args = strchr ( p, ' ' ); + } + else /* yes, even valid with trailing '"' missing */ + name_end = lpCmdLine+strlen(lpCmdLine); + } + else + { + name_beg = lpCmdLine; + args = strchr( lpCmdLine, ' ' ); + name_end = args ? args : lpCmdLine+strlen(lpCmdLine); + } + + if ((name_beg == lpCmdLine) && (!args)) + { /* just use the original cmdline string as file name */ + name = (LPSTR)lpCmdLine; + } + else + { + if (!(name = HeapAlloc( GetProcessHeap(), 0, name_end - name_beg + 1 ))) + return ERROR_NOT_ENOUGH_MEMORY; + memcpy( name, name_beg, name_end - name_beg ); + name[name_end - name_beg] = '\0'; + } + + if (args) + { + args++; + arglen = strlen(args); + cmdline = HeapAlloc( GetProcessHeap(), 0, 2 + arglen ); + cmdline[0] = (BYTE)arglen; + strcpy( cmdline + 1, args ); + } + else + { + cmdline = HeapAlloc( GetProcessHeap(), 0, 2 ); + cmdline[0] = cmdline[1] = 0; + } + + TRACE("name: '%s', cmdline: '%.*s'\n", name, cmdline[0], &cmdline[1]); + + if (SearchPathA( NULL, name, ".exe", sizeof(buffer), buffer, NULL )) + { + LOADPARAMS16 params; + WORD showCmd[2]; + showCmd[0] = 2; + showCmd[1] = nCmdShow; + + params.hEnvironment = 0; + params.cmdLine = MapLS( cmdline ); + params.showCmd = MapLS( showCmd ); + params.reserved = 0; + + ret = LoadModule16( buffer, ¶ms ); + UnMapLS( params.cmdLine ); + UnMapLS( params.showCmd ); + } + else ret = GetLastError(); + + HeapFree( GetProcessHeap(), 0, cmdline ); + if (name != lpCmdLine) HeapFree( GetProcessHeap(), 0, name ); + + if (ret == 21) /* 32-bit module */ + { + DWORD count; + ReleaseThunkLock( &count ); + ret = LOWORD( WinExec( lpCmdLine, nCmdShow ) ); + RestoreThunkLock( count ); + } + return ret; +} + +/********************************************************************** + * GetModuleHandle (KERNEL.47) + * + * Find a module from a module name. + * + * NOTE: The current implementation works the same way the Windows 95 one + * does. Do not try to 'fix' it, fix the callers. + * + It does not do ANY extension handling (except that strange .EXE bit)! + * + It does not care about paths, just about basenames. (same as Windows) + * + * RETURNS + * LOWORD: + * the win16 module handle if found + * 0 if not + * HIWORD (undocumented, see "Undocumented Windows", chapter 5): + * Always hFirstModule + */ +DWORD WINAPI WIN16_GetModuleHandle( SEGPTR name ) +{ + if (HIWORD(name) == 0) + return MAKELONG(GetExePtr( (HINSTANCE16)name), hFirstModule ); + return MAKELONG(GetModuleHandle16( MapSL(name)), hFirstModule ); +} + +/********************************************************************** + * NE_GetModuleByFilename + */ +static HMODULE16 NE_GetModuleByFilename( LPCSTR name ) +{ + HMODULE16 hModule; + LPSTR s, p; + BYTE len, *name_table; + char tmpstr[MAX_PATH]; + NE_MODULE *pModule; + + lstrcpynA(tmpstr, name, sizeof(tmpstr)); + + /* If the base filename of 'name' matches the base filename of the module + * filename of some module (case-insensitive compare): + * Return its handle. + */ + + /* basename: search backwards in passed name to \ / or : */ + s = tmpstr + strlen(tmpstr); + while (s > tmpstr) + { + if (s[-1]=='/' || s[-1]=='\\' || s[-1]==':') + break; + s--; + } + + /* search this in loaded filename list */ + for (hModule = hFirstModule; hModule ; hModule = pModule->next) + { + char *loadedfn; + OFSTRUCT *ofs; + + pModule = NE_GetPtr( hModule ); + if (!pModule) break; + if (!pModule->fileinfo) continue; + if (pModule->flags & NE_FFLAGS_WIN32) continue; + + ofs = (OFSTRUCT*)((BYTE *)pModule + pModule->fileinfo); + loadedfn = ((char*)ofs->szPathName) + strlen(ofs->szPathName); + /* basename: search backwards in pathname to \ / or : */ + while (loadedfn > (char*)ofs->szPathName) + { + if (loadedfn[-1]=='/' || loadedfn[-1]=='\\' || loadedfn[-1]==':') + break; + loadedfn--; + } + /* case insensitive compare ... */ + if (!FILE_strcasecmp(loadedfn, s)) + return hModule; + } + /* If basename (without ext) matches the module name of a module: + * Return its handle. + */ + + if ( (p = strrchr( s, '.' )) != NULL ) *p = '\0'; + len = strlen(s); + + for (hModule = hFirstModule; hModule ; hModule = pModule->next) + { + pModule = NE_GetPtr( hModule ); + if (!pModule) break; + if (pModule->flags & NE_FFLAGS_WIN32) continue; + + name_table = (BYTE *)pModule + pModule->name_table; + if ((*name_table == len) && !FILE_strncasecmp(s, name_table+1, len)) + return hModule; + } + + return 0; +} + +/*********************************************************************** + * GetProcAddress16 (KERNEL32.37) + * Get procaddress in 16bit module from win32... (kernel32 undoc. ordinal func) + */ +FARPROC16 WINAPI WIN32_GetProcAddress16( HMODULE hModule, LPCSTR name ) +{ + if (!hModule) return 0; + if (HIWORD(hModule)) + { + WARN("hModule is Win32 handle (%p)\n", hModule ); + return 0; + } + return GetProcAddress16( LOWORD(hModule), name ); +} + +/********************************************************************** + * ModuleFirst (TOOLHELP.59) + */ +BOOL16 WINAPI ModuleFirst16( MODULEENTRY *lpme ) +{ + lpme->wNext = hFirstModule; + return ModuleNext16( lpme ); +} + + +/********************************************************************** + * ModuleNext (TOOLHELP.60) + */ +BOOL16 WINAPI ModuleNext16( MODULEENTRY *lpme ) +{ + NE_MODULE *pModule; + char *name; + + if (!lpme->wNext) return FALSE; + if (!(pModule = NE_GetPtr( lpme->wNext ))) return FALSE; + name = (char *)pModule + pModule->name_table; + memcpy( lpme->szModule, name + 1, min(*name, MAX_MODULE_NAME) ); + lpme->szModule[min(*name, MAX_MODULE_NAME)] = '\0'; + lpme->hModule = lpme->wNext; + lpme->wcUsage = pModule->count; + lstrcpynA( lpme->szExePath, NE_MODULE_NAME(pModule), sizeof(lpme->szExePath) ); + lpme->wNext = pModule->next; + return TRUE; +} + + +/********************************************************************** + * ModuleFindName (TOOLHELP.61) + */ +BOOL16 WINAPI ModuleFindName16( MODULEENTRY *lpme, LPCSTR name ) +{ + lpme->wNext = GetModuleHandle16( name ); + return ModuleNext16( lpme ); +} + + +/********************************************************************** + * ModuleFindHandle (TOOLHELP.62) + */ +BOOL16 WINAPI ModuleFindHandle16( MODULEENTRY *lpme, HMODULE16 hModule ) +{ + hModule = GetExePtr( hModule ); + lpme->wNext = hModule; + return ModuleNext16( lpme ); +} + + +/*************************************************************************** + * IsRomModule (KERNEL.323) + */ +BOOL16 WINAPI IsRomModule16( HMODULE16 unused ) +{ + return FALSE; +} + +/*************************************************************************** + * IsRomFile (KERNEL.326) + */ +BOOL16 WINAPI IsRomFile16( HFILE16 unused ) +{ + return FALSE; +} + +/*********************************************************************** + * create_dummy_module + * + * Create a dummy NE module for Win32 or Winelib. + */ +static HMODULE16 create_dummy_module( HMODULE module32 ) +{ + HMODULE16 hModule; + NE_MODULE *pModule; + SEGTABLEENTRY *pSegment; + char *pStr,*s; + unsigned int len; + const char* basename; + OFSTRUCT *ofs; + int of_size, size; + char filename[MAX_PATH]; + IMAGE_NT_HEADERS *nt = RtlImageNtHeader( module32 ); + + if (!nt) return (HMODULE16)11; /* invalid exe */ + + /* Extract base filename */ + GetModuleFileNameA( module32, filename, sizeof(filename) ); + basename = strrchr(filename, '\\'); + if (!basename) basename = filename; + else basename++; + len = strlen(basename); + if ((s = strchr(basename, '.'))) len = s - basename; + + /* Allocate module */ + of_size = sizeof(OFSTRUCT) - sizeof(ofs->szPathName) + + strlen(filename) + 1; + size = sizeof(NE_MODULE) + + /* loaded file info */ + ((of_size + 3) & ~3) + + /* segment table: DS,CS */ + 2 * sizeof(SEGTABLEENTRY) + + /* name table */ + len + 2 + + /* several empty tables */ + 8; + + hModule = GlobalAlloc16( GMEM_MOVEABLE | GMEM_ZEROINIT, size ); + if (!hModule) return (HMODULE16)11; /* invalid exe */ + + FarSetOwner16( hModule, hModule ); + pModule = (NE_MODULE *)GlobalLock16( hModule ); + + /* Set all used entries */ + pModule->magic = IMAGE_OS2_SIGNATURE; + pModule->count = 1; + pModule->next = 0; + pModule->flags = NE_FFLAGS_WIN32; + pModule->dgroup = 0; + pModule->ss = 1; + pModule->cs = 2; + pModule->heap_size = 0; + pModule->stack_size = 0; + pModule->seg_count = 2; + pModule->modref_count = 0; + pModule->nrname_size = 0; + pModule->fileinfo = sizeof(NE_MODULE); + pModule->os_flags = NE_OSFLAGS_WINDOWS; + pModule->self = hModule; + pModule->module32 = module32; + + /* Set version and flags */ + pModule->expected_version = ((nt->OptionalHeader.MajorSubsystemVersion & 0xff) << 8 ) | + (nt->OptionalHeader.MinorSubsystemVersion & 0xff); + if (nt->FileHeader.Characteristics & IMAGE_FILE_DLL) + pModule->flags |= NE_FFLAGS_LIBMODULE | NE_FFLAGS_SINGLEDATA; + + /* Set loaded file information */ + ofs = (OFSTRUCT *)(pModule + 1); + memset( ofs, 0, of_size ); + ofs->cBytes = of_size < 256 ? of_size : 255; /* FIXME */ + strcpy( ofs->szPathName, filename ); + + pSegment = (SEGTABLEENTRY*)((char*)(pModule + 1) + ((of_size + 3) & ~3)); + pModule->seg_table = (int)pSegment - (int)pModule; + /* Data segment */ + pSegment->size = 0; + pSegment->flags = NE_SEGFLAGS_DATA; + pSegment->minsize = 0x1000; + pSegment++; + /* Code segment */ + pSegment->flags = 0; + pSegment++; + + /* Module name */ + pStr = (char *)pSegment; + pModule->name_table = (int)pStr - (int)pModule; + assert(len<256); + *pStr = len; + lstrcpynA( pStr+1, basename, len+1 ); + pStr += len+2; + + /* All tables zero terminated */ + pModule->res_table = pModule->import_table = pModule->entry_table = (int)pStr - (int)pModule; + + NE_RegisterModule( pModule ); + LoadLibraryA( filename ); /* increment the ref count of the 32-bit module */ + return hModule; +} + +/*********************************************************************** + * PrivateLoadLibrary (KERNEL32.@) + * + * FIXME: rough guesswork, don't know what "Private" means + */ +HINSTANCE16 WINAPI PrivateLoadLibrary(LPCSTR libname) +{ + return LoadLibrary16(libname); +} + +/*********************************************************************** + * PrivateFreeLibrary (KERNEL32.@) + * + * FIXME: rough guesswork, don't know what "Private" means + */ +void WINAPI PrivateFreeLibrary(HINSTANCE16 handle) +{ + FreeLibrary16(handle); +} + +/*************************************************************************** + * MapHModuleLS (KERNEL32.@) + */ +HMODULE16 WINAPI MapHModuleLS(HMODULE hmod) +{ + HMODULE16 ret; + NE_MODULE *pModule; + + if (!hmod) + return TASK_GetCurrent()->hInstance; + if (!HIWORD(hmod)) + return LOWORD(hmod); /* we already have a 16 bit module handle */ + pModule = (NE_MODULE*)GlobalLock16(hFirstModule); + while (pModule) { + if (pModule->module32 == hmod) + return pModule->self; + pModule = (NE_MODULE*)GlobalLock16(pModule->next); + } + if ((ret = create_dummy_module( hmod )) < 32) + { + SetLastError(ret); + ret = 0; + } + return ret; +} + +/*************************************************************************** + * MapHModuleSL (KERNEL32.@) + */ +HMODULE WINAPI MapHModuleSL(HMODULE16 hmod) +{ + NE_MODULE *pModule; + + if (!hmod) { + TDB *pTask = TASK_GetCurrent(); + hmod = pTask->hModule; + } + pModule = (NE_MODULE*)GlobalLock16(hmod); + if ((pModule->magic!=IMAGE_OS2_SIGNATURE) || !(pModule->flags & NE_FFLAGS_WIN32)) + return 0; + return pModule->module32; +} + +/*************************************************************************** + * MapHInstLS (KERNEL32.@) + * MapHInstLS (KERNEL.472) + */ +void WINAPI MapHInstLS( CONTEXT86 *context ) +{ + context->Eax = MapHModuleLS( (HMODULE)context->Eax ); +} + +/*************************************************************************** + * MapHInstSL (KERNEL32.@) + * MapHInstSL (KERNEL.473) + */ +void WINAPI MapHInstSL( CONTEXT86 *context ) +{ + context->Eax = (DWORD)MapHModuleSL( context->Eax ); +} + +/*************************************************************************** + * MapHInstLS_PN (KERNEL32.@) + */ +void WINAPI MapHInstLS_PN( CONTEXT86 *context ) +{ + if (context->Eax) context->Eax = MapHModuleLS( (HMODULE)context->Eax ); +} + +/*************************************************************************** + * MapHInstSL_PN (KERNEL32.@) + */ +void WINAPI MapHInstSL_PN( CONTEXT86 *context ) +{ + if (context->Eax) context->Eax = (DWORD)MapHModuleSL( context->Eax ); +} diff --git a/loader/ne/segment.c b/dlls/kernel/ne_segment.c similarity index 98% rename from loader/ne/segment.c rename to dlls/kernel/ne_segment.c index 83fce736fd9..061f4a69594 100644 --- a/loader/ne/segment.c +++ b/dlls/kernel/ne_segment.c @@ -34,6 +34,7 @@ #include #include "wine/winbase16.h" +#include "wownt32.h" #include "wine/library.h" #include "global.h" #include "task.h" @@ -82,10 +83,6 @@ struct relocation_entry_s static void NE_FixupSegmentPrologs(NE_MODULE *pModule, WORD segnum); -/* ### start build ### */ -extern WORD CALLBACK NE_CallTo16_word_ww(FARPROC16,WORD,WORD); -extern WORD CALLBACK NE_CallTo16_word_www(FARPROC16,WORD,WORD,WORD); -/* ### stop build ### */ /*********************************************************************** * NE_GetRelocAddrName @@ -158,6 +155,8 @@ BOOL NE_LoadSegment( NE_MODULE *pModule, WORD segnum ) DWORD oldstack; HANDLE hFile32; HFILE16 hFile16; + WORD args[3]; + DWORD ret; selfloadheader = MapSL( MAKESEGPTR(SEL(pSegTable->hSeg),0) ); oldstack = NtCurrentTeb()->cur_stack; @@ -169,8 +168,11 @@ BOOL NE_LoadSegment( NE_MODULE *pModule, WORD segnum ) DuplicateHandle( GetCurrentProcess(), hf, GetCurrentProcess(), &hFile32, 0, FALSE, DUPLICATE_SAME_ACCESS ); hFile16 = Win32HandleToDosFileHandle( hFile32 ); - pSeg->hSeg = NE_CallTo16_word_www( selfloadheader->LoadAppSeg, - pModule->self, hFile16, segnum ); + args[2] = pModule->self; + args[1] = hFile16; + args[0] = segnum; + WOWCallback16Ex( (DWORD)selfloadheader->LoadAppSeg, WCB16_PASCAL, sizeof(args), args, &ret ); + pSeg->hSeg = LOWORD(ret); TRACE_(dll)("Ret CallLoadAppSegProc: hSeg = 0x%04x\n", pSeg->hSeg); _lclose16( hFile16 ); NtCurrentTeb()->cur_stack = oldstack; @@ -450,6 +452,7 @@ BOOL NE_LoadAllSegments( NE_MODULE *pModule ) SELFLOADHEADER *selfloadheader; HMODULE16 mod = GetModuleHandle16("KERNEL"); DWORD oldstack; + WORD args[2]; TRACE_(module)("%.*s is a self-loading module!\n", *((BYTE*)pModule + pModule->name_table), @@ -470,7 +473,9 @@ BOOL NE_LoadAllSegments( NE_MODULE *pModule ) hFile16 = Win32HandleToDosFileHandle( hf ); TRACE_(dll)("CallBootAppProc(hModule=0x%04x,hf=0x%04x)\n", pModule->self,hFile16); - NE_CallTo16_word_ww(selfloadheader->BootApp, pModule->self,hFile16); + args[1] = pModule->self; + args[0] = hFile16; + WOWCallback16Ex( (DWORD)selfloadheader->BootApp, WCB16_PASCAL, sizeof(args), args, NULL ); TRACE_(dll)("Return from CallBootAppProc\n"); _lclose16(hFile16); NtCurrentTeb()->cur_stack = oldstack; diff --git a/dlls/kernel/task.c b/dlls/kernel/task.c new file mode 100644 index 00000000000..44b4ebc5ea8 --- /dev/null +++ b/dlls/kernel/task.c @@ -0,0 +1,1556 @@ +/* + * Task functions + * + * Copyright 1995 Alexandre Julliard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "config.h" +#include "wine/port.h" + +#include +#include +#include +#ifdef HAVE_UNISTD_H +# include +#endif + +#include "winbase.h" +#include "wingdi.h" +#include "winnt.h" +#include "wownt32.h" +#include "winuser.h" + +#include "wine/winbase16.h" +#include "drive.h" +#include "file.h" +#include "global.h" +#include "instance.h" +#include "module.h" +#include "winternl.h" +#include "selectors.h" +#include "wine/server.h" +#include "syslevel.h" +#include "stackframe.h" +#include "task.h" +#include "thread.h" +#include "toolhelp.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(task); +WINE_DECLARE_DEBUG_CHANNEL(relay); +WINE_DECLARE_DEBUG_CHANNEL(toolhelp); + + /* Min. number of thunks allocated when creating a new segment */ +#define MIN_THUNKS 32 + +static THHOOK DefaultThhook; + +#define hFirstTask (pThhook->HeadTDB) +#define hLockedTask (pThhook->LockTDB) + +static UINT16 nTaskCount = 0; + +static HTASK16 initial_task; + +/*********************************************************************** + * TASK_InstallTHHook + */ +void TASK_InstallTHHook( THHOOK *pNewThhook ) +{ + THHOOK *pOldThhook = pThhook; + + pThhook = pNewThhook? pNewThhook : &DefaultThhook; + + *pThhook = *pOldThhook; +} + +/*********************************************************************** + * TASK_GetPtr + */ +static TDB *TASK_GetPtr( HTASK16 hTask ) +{ + return GlobalLock16( hTask ); +} + + +/*********************************************************************** + * TASK_GetCurrent + */ +TDB *TASK_GetCurrent(void) +{ + return TASK_GetPtr( GetCurrentTask() ); +} + + +/*********************************************************************** + * TASK_LinkTask + */ +static void TASK_LinkTask( HTASK16 hTask ) +{ + HTASK16 *prevTask; + TDB *pTask; + + if (!(pTask = TASK_GetPtr( hTask ))) return; + prevTask = &hFirstTask; + while (*prevTask) + { + TDB *prevTaskPtr = TASK_GetPtr( *prevTask ); + if (prevTaskPtr->priority >= pTask->priority) break; + prevTask = &prevTaskPtr->hNext; + } + pTask->hNext = *prevTask; + *prevTask = hTask; + nTaskCount++; +} + + +/*********************************************************************** + * TASK_UnlinkTask + */ +static void TASK_UnlinkTask( HTASK16 hTask ) +{ + HTASK16 *prevTask; + TDB *pTask; + + prevTask = &hFirstTask; + while (*prevTask && (*prevTask != hTask)) + { + pTask = TASK_GetPtr( *prevTask ); + prevTask = &pTask->hNext; + } + if (*prevTask) + { + pTask = TASK_GetPtr( *prevTask ); + *prevTask = pTask->hNext; + pTask->hNext = 0; + nTaskCount--; + } +} + + +/*********************************************************************** + * TASK_CreateThunks + * + * Create a thunk free-list in segment 'handle', starting from offset 'offset' + * and containing 'count' entries. + */ +static void TASK_CreateThunks( HGLOBAL16 handle, WORD offset, WORD count ) +{ + int i; + WORD free; + THUNKS *pThunk; + + pThunk = (THUNKS *)((BYTE *)GlobalLock16( handle ) + offset); + pThunk->next = 0; + pThunk->magic = THUNK_MAGIC; + pThunk->free = (int)&pThunk->thunks - (int)pThunk; + free = pThunk->free; + for (i = 0; i < count-1; i++) + { + free += 8; /* Offset of next thunk */ + pThunk->thunks[4*i] = free; + } + pThunk->thunks[4*i] = 0; /* Last thunk */ +} + + +/*********************************************************************** + * TASK_AllocThunk + * + * Allocate a thunk for MakeProcInstance(). + */ +static SEGPTR TASK_AllocThunk(void) +{ + TDB *pTask; + THUNKS *pThunk; + WORD sel, base; + + if (!(pTask = TASK_GetCurrent())) return 0; + sel = pTask->hCSAlias; + pThunk = &pTask->thunks; + base = (int)pThunk - (int)pTask; + while (!pThunk->free) + { + sel = pThunk->next; + if (!sel) /* Allocate a new segment */ + { + sel = GLOBAL_Alloc( GMEM_FIXED, sizeof(THUNKS) + (MIN_THUNKS-1)*8, + pTask->hPDB, WINE_LDT_FLAGS_CODE ); + if (!sel) return (SEGPTR)0; + TASK_CreateThunks( sel, 0, MIN_THUNKS ); + pThunk->next = sel; + } + pThunk = (THUNKS *)GlobalLock16( sel ); + base = 0; + } + base += pThunk->free; + pThunk->free = *(WORD *)((BYTE *)pThunk + pThunk->free); + return MAKESEGPTR( sel, base ); +} + + +/*********************************************************************** + * TASK_FreeThunk + * + * Free a MakeProcInstance() thunk. + */ +static BOOL TASK_FreeThunk( SEGPTR thunk ) +{ + TDB *pTask; + THUNKS *pThunk; + WORD sel, base; + + if (!(pTask = TASK_GetCurrent())) return 0; + sel = pTask->hCSAlias; + pThunk = &pTask->thunks; + base = (int)pThunk - (int)pTask; + while (sel && (sel != HIWORD(thunk))) + { + sel = pThunk->next; + pThunk = (THUNKS *)GlobalLock16( sel ); + base = 0; + } + if (!sel) return FALSE; + *(WORD *)((BYTE *)pThunk + LOWORD(thunk) - base) = pThunk->free; + pThunk->free = LOWORD(thunk) - base; + return TRUE; +} + + +/*********************************************************************** + * TASK_Create + * + * NOTE: This routine might be called by a Win32 thread. Thus, we need + * to be careful to protect global data structures. We do this + * by entering the Win16Lock while linking the task into the + * global task list. + */ +static TDB *TASK_Create( NE_MODULE *pModule, UINT16 cmdShow, TEB *teb, LPCSTR cmdline, BYTE len ) +{ + HTASK16 hTask; + TDB *pTask; + FARPROC16 proc; + HMODULE16 hModule = pModule ? pModule->self : 0; + + /* Allocate the task structure */ + + hTask = GlobalAlloc16( GMEM_FIXED | GMEM_ZEROINIT, sizeof(TDB) ); + if (!hTask) return NULL; + pTask = TASK_GetPtr( hTask ); + FarSetOwner16( hTask, hModule ); + + /* Fill the task structure */ + + pTask->hSelf = hTask; + + if (teb && teb->tibflags & TEBF_WIN32) + { + pTask->flags |= TDBF_WIN32; + pTask->hInstance = hModule; + pTask->hPrevInstance = 0; + /* NOTE: for 16-bit tasks, the instance handles are updated later on + in NE_InitProcess */ + } + + pTask->version = pModule ? pModule->expected_version : 0x0400; + pTask->hModule = hModule; + pTask->hParent = GetCurrentTask(); + pTask->magic = TDB_MAGIC; + pTask->nCmdShow = cmdShow; + pTask->teb = teb; + pTask->curdrive = DRIVE_GetCurrentDrive() | 0x80; + strcpy( pTask->curdir, "\\" ); + WideCharToMultiByte(CP_ACP, 0, DRIVE_GetDosCwd(DRIVE_GetCurrentDrive()), -1, + pTask->curdir + 1, sizeof(pTask->curdir) - 1, NULL, NULL); + pTask->curdir[sizeof(pTask->curdir) - 1] = 0; /* ensure 0 termination */ + + /* Create the thunks block */ + + TASK_CreateThunks( hTask, (int)&pTask->thunks - (int)pTask, 7 ); + + /* Copy the module name */ + + if (hModule) + { + char name[10]; + GetModuleName16( hModule, name, sizeof(name) ); + strncpy( pTask->module_name, name, sizeof(pTask->module_name) ); + pTask->compat_flags = GetProfileIntA( "Compatibility", name, 0 ); + } + + /* Allocate a selector for the PDB */ + + pTask->hPDB = GLOBAL_CreateBlock( GMEM_FIXED, &pTask->pdb, sizeof(PDB16), + hModule, WINE_LDT_FLAGS_DATA ); + + /* Fill the PDB */ + + pTask->pdb.int20 = 0x20cd; + pTask->pdb.dispatcher[0] = 0x9a; /* ljmp */ + proc = GetProcAddress16( GetModuleHandle16("KERNEL"), "DOS3Call" ); + memcpy( &pTask->pdb.dispatcher[1], &proc, sizeof(proc) ); + pTask->pdb.savedint22 = 0; + pTask->pdb.savedint23 = 0; + pTask->pdb.savedint24 = 0; + pTask->pdb.fileHandlesPtr = + MAKESEGPTR( GlobalHandleToSel16(pTask->hPDB), (int)&((PDB16 *)0)->fileHandles ); + pTask->pdb.hFileHandles = 0; + memset( pTask->pdb.fileHandles, 0xff, sizeof(pTask->pdb.fileHandles) ); + /* FIXME: should we make a copy of the environment? */ + pTask->pdb.environment = SELECTOROF(GetDOSEnvironment16()); + pTask->pdb.nbFiles = 20; + + /* Fill the command line */ + + if (!cmdline) + { + cmdline = GetCommandLineA(); + /* remove the first word (program name) */ + if (*cmdline == '"') + if (!(cmdline = strchr( cmdline+1, '"' ))) cmdline = GetCommandLineA(); + while (*cmdline && (*cmdline != ' ') && (*cmdline != '\t')) cmdline++; + while ((*cmdline == ' ') || (*cmdline == '\t')) cmdline++; + len = strlen(cmdline); + } + if (len >= sizeof(pTask->pdb.cmdLine)) len = sizeof(pTask->pdb.cmdLine)-1; + pTask->pdb.cmdLine[0] = len; + memcpy( pTask->pdb.cmdLine + 1, cmdline, len ); + /* pTask->pdb.cmdLine[len+1] = 0; */ + + TRACE("cmdline='%.*s' task=%04x\n", len, cmdline, hTask ); + + /* Allocate a code segment alias for the TDB */ + + pTask->hCSAlias = GLOBAL_CreateBlock( GMEM_FIXED, (void *)pTask, + sizeof(TDB), pTask->hPDB, WINE_LDT_FLAGS_CODE ); + + /* Default DTA overwrites command line */ + + pTask->dta = MAKESEGPTR( pTask->hPDB, (int)&pTask->pdb.cmdLine - (int)&pTask->pdb ); + + /* Create scheduler event for 16-bit tasks */ + + if ( !(pTask->flags & TDBF_WIN32) ) + NtCreateEvent( &pTask->hEvent, EVENT_ALL_ACCESS, NULL, TRUE, FALSE ); + + /* Enter task handle into thread */ + + if (teb) teb->htask16 = hTask; + if (!initial_task) initial_task = hTask; + + return pTask; +} + + +/*********************************************************************** + * TASK_DeleteTask + */ +static void TASK_DeleteTask( HTASK16 hTask ) +{ + TDB *pTask; + HGLOBAL16 hPDB; + + if (!(pTask = TASK_GetPtr( hTask ))) return; + hPDB = pTask->hPDB; + + pTask->magic = 0xdead; /* invalidate signature */ + + /* Free the selector aliases */ + + GLOBAL_FreeBlock( pTask->hCSAlias ); + GLOBAL_FreeBlock( pTask->hPDB ); + + /* Free the task module */ + + FreeModule16( pTask->hModule ); + + /* Free the task structure itself */ + + GlobalFree16( hTask ); + + /* Free all memory used by this task (including the 32-bit stack, */ + /* the environment block and the thunk segments). */ + + GlobalFreeAll16( hPDB ); +} + + +/*********************************************************************** + * TASK_CreateMainTask + * + * Create a task for the main (32-bit) process. + */ +void TASK_CreateMainTask(void) +{ + TDB *pTask; + STARTUPINFOA startup_info; + UINT cmdShow = 1; /* SW_SHOWNORMAL but we don't want to include winuser.h here */ + + GetStartupInfoA( &startup_info ); + if (startup_info.dwFlags & STARTF_USESHOWWINDOW) cmdShow = startup_info.wShowWindow; + pTask = TASK_Create( NULL, cmdShow, NtCurrentTeb(), NULL, 0 ); + if (!pTask) + { + ERR("could not create task for main process\n"); + ExitProcess(1); + } + + /* Add the task to the linked list */ + /* (no need to get the win16 lock, we are the only thread at this point) */ + TASK_LinkTask( pTask->hSelf ); +} + + +/* startup routine for a new 16-bit thread */ +static DWORD CALLBACK task_start( TDB *pTask ) +{ + DWORD ret; + + NtCurrentTeb()->tibflags &= ~TEBF_WIN32; + NtCurrentTeb()->htask16 = pTask->hSelf; + + _EnterWin16Lock(); + TASK_LinkTask( pTask->hSelf ); + pTask->teb = NtCurrentTeb(); + ret = NE_StartTask(); + _LeaveWin16Lock(); + return ret; +} + + +/*********************************************************************** + * TASK_SpawnTask + * + * Spawn a new 16-bit task. + */ +HTASK16 TASK_SpawnTask( NE_MODULE *pModule, WORD cmdShow, + LPCSTR cmdline, BYTE len, HANDLE *hThread ) +{ + TDB *pTask; + + if (!(pTask = TASK_Create( pModule, cmdShow, NULL, cmdline, len ))) return 0; + if (!(*hThread = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)task_start, pTask, 0, NULL ))) + { + TASK_DeleteTask( pTask->hSelf ); + return 0; + } + return pTask->hSelf; +} + + +/*********************************************************************** + * TASK_GetTaskFromThread + */ +HTASK16 TASK_GetTaskFromThread( DWORD thread ) +{ + TDB *p = TASK_GetPtr( hFirstTask ); + while (p) + { + if (p->teb->tid == thread) return p->hSelf; + p = TASK_GetPtr( p->hNext ); + } + return 0; +} + + +/*********************************************************************** + * TASK_CallTaskSignalProc + */ +static void TASK_CallTaskSignalProc( UINT16 uCode, HANDLE16 hTaskOrModule ) +{ + WORD args[5]; + TDB *pTask = TASK_GetCurrent(); + + if ( !pTask || !pTask->userhandler ) return; + + args[4] = hTaskOrModule; + args[3] = uCode; + args[2] = 0; + args[1] = pTask->hInstance; + args[0] = pTask->hQueue; + WOWCallback16Ex( (DWORD)pTask->userhandler, WCB16_PASCAL, sizeof(args), args, NULL ); +} + + +/*********************************************************************** + * TASK_ExitTask + */ +void TASK_ExitTask(void) +{ + TDB *pTask; + DWORD lockCount; + + /* Enter the Win16Lock to protect global data structures */ + _EnterWin16Lock(); + + pTask = TASK_GetCurrent(); + if ( !pTask ) + { + _LeaveWin16Lock(); + return; + } + + TRACE("Killing task %04x\n", pTask->hSelf ); + + /* Perform USER cleanup */ + + TASK_CallTaskSignalProc( USIG16_TERMINATION, pTask->hSelf ); + + /* Remove the task from the list to be sure we never switch back to it */ + TASK_UnlinkTask( pTask->hSelf ); + + if (!nTaskCount || (nTaskCount == 1 && hFirstTask == initial_task)) + { + TRACE("this is the last task, exiting\n" ); + ExitKernel16(); + } + + pTask->nEvents = 0; + + if ( hLockedTask == pTask->hSelf ) + hLockedTask = 0; + + TASK_DeleteTask( pTask->hSelf ); + + /* ... and completely release the Win16Lock, just in case. */ + ReleaseThunkLock( &lockCount ); +} + + +/*********************************************************************** + * ExitKernel (KERNEL.2) + * + * Clean-up everything and exit the Wine process. + */ +void WINAPI ExitKernel16(void) +{ + WriteOutProfiles16(); + TerminateProcess( GetCurrentProcess(), 0 ); +} + + +/*********************************************************************** + * InitTask (KERNEL.91) + * + * Called by the application startup code. + */ +void WINAPI InitTask16( CONTEXT86 *context ) +{ + TDB *pTask; + INSTANCEDATA *pinstance; + SEGPTR ptr; + + context->Eax = 0; + if (!(pTask = TASK_GetCurrent())) return; + + /* Note: we need to trust that BX/CX contain the stack/heap sizes, + as some apps, notably Visual Basic apps, *modify* the heap/stack + size of the instance data segment before calling InitTask() */ + + /* Initialize the INSTANCEDATA structure */ + pinstance = MapSL( MAKESEGPTR(CURRENT_DS, 0) ); + pinstance->stackmin = OFFSETOF( pTask->teb->cur_stack ) + sizeof( STACK16FRAME ); + pinstance->stackbottom = pinstance->stackmin; /* yup, that's right. Confused me too. */ + pinstance->stacktop = ( pinstance->stackmin > LOWORD(context->Ebx) ? + pinstance->stackmin - LOWORD(context->Ebx) : 0 ) + 150; + + /* Initialize the local heap */ + if (LOWORD(context->Ecx)) + LocalInit16( GlobalHandleToSel16(pTask->hInstance), 0, LOWORD(context->Ecx) ); + + /* Initialize implicitly loaded DLLs */ + NE_InitializeDLLs( pTask->hModule ); + NE_DllProcessAttach( pTask->hModule ); + + /* Registers on return are: + * ax 1 if OK, 0 on error + * cx stack limit in bytes + * dx cmdShow parameter + * si instance handle of the previous instance + * di instance handle of the new task + * es:bx pointer to command line inside PSP + * + * 0 (=%bp) is pushed on the stack + */ + ptr = stack16_push( sizeof(WORD) ); + *(WORD *)MapSL(ptr) = 0; + context->Esp -= 2; + + context->Eax = 1; + + if (!pTask->pdb.cmdLine[0]) context->Ebx = 0x80; + else + { + LPBYTE p = &pTask->pdb.cmdLine[1]; + while ((*p == ' ') || (*p == '\t')) p++; + context->Ebx = 0x80 + (p - pTask->pdb.cmdLine); + } + context->Ecx = pinstance->stacktop; + context->Edx = pTask->nCmdShow; + context->Esi = (DWORD)pTask->hPrevInstance; + context->Edi = (DWORD)pTask->hInstance; + context->SegEs = (WORD)pTask->hPDB; +} + + +/*********************************************************************** + * WaitEvent (KERNEL.30) + */ +BOOL16 WINAPI WaitEvent16( HTASK16 hTask ) +{ + TDB *pTask; + + if (!hTask) hTask = GetCurrentTask(); + pTask = TASK_GetPtr( hTask ); + + if (pTask->flags & TDBF_WIN32) + { + FIXME("called for Win32 thread (%04x)!\n", NtCurrentTeb()->teb_sel); + return TRUE; + } + + if (pTask->nEvents > 0) + { + pTask->nEvents--; + return FALSE; + } + + if (pTask->teb == NtCurrentTeb()) + { + DWORD lockCount; + + NtResetEvent( pTask->hEvent, NULL ); + ReleaseThunkLock( &lockCount ); + SYSLEVEL_CheckNotLevel( 1 ); + WaitForSingleObject( pTask->hEvent, INFINITE ); + RestoreThunkLock( lockCount ); + if (pTask->nEvents > 0) pTask->nEvents--; + } + else FIXME("for other task %04x cur=%04x\n",pTask->hSelf,GetCurrentTask()); + + return TRUE; +} + + +/*********************************************************************** + * PostEvent (KERNEL.31) + */ +void WINAPI PostEvent16( HTASK16 hTask ) +{ + TDB *pTask; + + if (!hTask) hTask = GetCurrentTask(); + if (!(pTask = TASK_GetPtr( hTask ))) return; + + if (pTask->flags & TDBF_WIN32) + { + FIXME("called for Win32 thread (%04x)!\n", pTask->teb->teb_sel ); + return; + } + + pTask->nEvents++; + + if (pTask->nEvents == 1) NtSetEvent( pTask->hEvent, NULL ); +} + + +/*********************************************************************** + * SetPriority (KERNEL.32) + */ +void WINAPI SetPriority16( HTASK16 hTask, INT16 delta ) +{ + TDB *pTask; + INT16 newpriority; + + if (!hTask) hTask = GetCurrentTask(); + if (!(pTask = TASK_GetPtr( hTask ))) return; + newpriority = pTask->priority + delta; + if (newpriority < -32) newpriority = -32; + else if (newpriority > 15) newpriority = 15; + + pTask->priority = newpriority + 1; + TASK_UnlinkTask( pTask->hSelf ); + TASK_LinkTask( pTask->hSelf ); + pTask->priority--; +} + + +/*********************************************************************** + * LockCurrentTask (KERNEL.33) + */ +HTASK16 WINAPI LockCurrentTask16( BOOL16 bLock ) +{ + if (bLock) hLockedTask = GetCurrentTask(); + else hLockedTask = 0; + return hLockedTask; +} + + +/*********************************************************************** + * IsTaskLocked (KERNEL.122) + */ +HTASK16 WINAPI IsTaskLocked16(void) +{ + return hLockedTask; +} + + +/*********************************************************************** + * OldYield (KERNEL.117) + */ +void WINAPI OldYield16(void) +{ + DWORD count; + + ReleaseThunkLock(&count); + RestoreThunkLock(count); +} + +/*********************************************************************** + * WIN32_OldYield (KERNEL.447) + */ +void WINAPI WIN32_OldYield16(void) +{ + DWORD count; + + ReleaseThunkLock(&count); + RestoreThunkLock(count); +} + +/*********************************************************************** + * DirectedYield (KERNEL.150) + */ +void WINAPI DirectedYield16( HTASK16 hTask ) +{ + OldYield16(); +} + +/*********************************************************************** + * Yield (KERNEL.29) + */ +void WINAPI Yield16(void) +{ + TDB *pCurTask = TASK_GetCurrent(); + + if (pCurTask && pCurTask->hQueue) + { + HMODULE mod = GetModuleHandleA( "user32.dll" ); + if (mod) + { + FARPROC proc = GetProcAddress( mod, "UserYield16" ); + if (proc) + { + proc(); + return; + } + } + } + OldYield16(); +} + +/*********************************************************************** + * KERNEL_490 (KERNEL.490) + */ +HTASK16 WINAPI KERNEL_490( HTASK16 someTask ) +{ + if ( !someTask ) return 0; + + FIXME("(%04x): stub\n", someTask ); + return 0; +} + +/*********************************************************************** + * MakeProcInstance (KERNEL.51) + */ +FARPROC16 WINAPI MakeProcInstance16( FARPROC16 func, HANDLE16 hInstance ) +{ + BYTE *thunk,*lfunc; + SEGPTR thunkaddr; + WORD hInstanceSelector; + + hInstanceSelector = GlobalHandleToSel16(hInstance); + + TRACE("(%08lx, %04x);\n", (DWORD)func, hInstance); + + if (!HIWORD(func)) { + /* Win95 actually protects via SEH, but this is better for debugging */ + WARN("Ouch ! Called with invalid func 0x%08lx !\n", (DWORD)func); + return (FARPROC16)0; + } + + if ( (GlobalHandleToSel16(CURRENT_DS) != hInstanceSelector) + && (hInstance != 0) + && (hInstance != 0xffff) ) + { + /* calling MPI with a foreign DSEG is invalid ! */ + WARN("Problem with hInstance? Got %04x, using %04x instead\n", + hInstance,CURRENT_DS); + } + + /* Always use the DSEG that MPI was entered with. + * We used to set hInstance to GetTaskDS16(), but this should be wrong + * as CURRENT_DS provides the DSEG value we need. + * ("calling" DS, *not* "task" DS !) */ + hInstanceSelector = CURRENT_DS; + hInstance = GlobalHandle16(hInstanceSelector); + + /* no thunking for DLLs */ + if (NE_GetPtr(FarGetOwner16(hInstance))->flags & NE_FFLAGS_LIBMODULE) + return func; + + thunkaddr = TASK_AllocThunk(); + if (!thunkaddr) return (FARPROC16)0; + thunk = MapSL( thunkaddr ); + lfunc = MapSL( (SEGPTR)func ); + + TRACE("(%08lx,%04x): got thunk %08lx\n", + (DWORD)func, hInstance, (DWORD)thunkaddr ); + if (((lfunc[0]==0x8c) && (lfunc[1]==0xd8)) || /* movw %ds, %ax */ + ((lfunc[0]==0x1e) && (lfunc[1]==0x58)) /* pushw %ds, popw %ax */ + ) { + WARN("This was the (in)famous \"thunk useless\" warning. We thought we have to overwrite with nop;nop;, but this isn't true.\n"); + } + + *thunk++ = 0xb8; /* movw instance, %ax */ + *thunk++ = (BYTE)(hInstanceSelector & 0xff); + *thunk++ = (BYTE)(hInstanceSelector >> 8); + *thunk++ = 0xea; /* ljmp func */ + *(DWORD *)thunk = (DWORD)func; + return (FARPROC16)thunkaddr; + /* CX reg indicates if thunkaddr != NULL, implement if needed */ +} + + +/*********************************************************************** + * FreeProcInstance (KERNEL.52) + */ +void WINAPI FreeProcInstance16( FARPROC16 func ) +{ + TRACE("(%08lx)\n", (DWORD)func ); + TASK_FreeThunk( (SEGPTR)func ); +} + +/********************************************************************** + * TASK_GetCodeSegment + * + * Helper function for GetCodeHandle/GetCodeInfo: Retrieve the module + * and logical segment number of a given code segment. + * + * 'proc' either *is* already a pair of module handle and segment number, + * in which case there's nothing to do. Otherwise, it is a pointer to + * a function, and we need to retrieve the code segment. If the pointer + * happens to point to a thunk, we'll retrieve info about the code segment + * where the function pointed to by the thunk resides, not the thunk itself. + * + * FIXME: if 'proc' is a SNOOP16 return stub, we should retrieve info about + * the function the snoop code will return to ... + * + */ +static BOOL TASK_GetCodeSegment( FARPROC16 proc, NE_MODULE **ppModule, + SEGTABLEENTRY **ppSeg, int *pSegNr ) +{ + NE_MODULE *pModule = NULL; + SEGTABLEENTRY *pSeg = NULL; + int segNr=0; + + /* Try pair of module handle / segment number */ + pModule = (NE_MODULE *) GlobalLock16( HIWORD( proc ) ); + if ( pModule && pModule->magic == IMAGE_OS2_SIGNATURE ) + { + segNr = LOWORD( proc ); + if ( segNr && segNr <= pModule->seg_count ) + pSeg = NE_SEG_TABLE( pModule ) + segNr-1; + } + + /* Try thunk or function */ + else + { + BYTE *thunk = MapSL( (SEGPTR)proc ); + WORD selector; + + if ((thunk[0] == 0xb8) && (thunk[3] == 0xea)) + selector = thunk[6] + (thunk[7] << 8); + else + selector = HIWORD( proc ); + + pModule = NE_GetPtr( GlobalHandle16( selector ) ); + pSeg = pModule? NE_SEG_TABLE( pModule ) : NULL; + + if ( pModule ) + for ( segNr = 1; segNr <= pModule->seg_count; segNr++, pSeg++ ) + if ( GlobalHandleToSel16(pSeg->hSeg) == selector ) + break; + + if ( pModule && segNr > pModule->seg_count ) + pSeg = NULL; + } + + /* Abort if segment not found */ + + if ( !pModule || !pSeg ) + return FALSE; + + /* Return segment data */ + + if ( ppModule ) *ppModule = pModule; + if ( ppSeg ) *ppSeg = pSeg; + if ( pSegNr ) *pSegNr = segNr; + + return TRUE; +} + +/********************************************************************** + * GetCodeHandle (KERNEL.93) + */ +HANDLE16 WINAPI GetCodeHandle16( FARPROC16 proc ) +{ + SEGTABLEENTRY *pSeg; + + if ( !TASK_GetCodeSegment( proc, NULL, &pSeg, NULL ) ) + return (HANDLE16)0; + + return pSeg->hSeg; +} + +/********************************************************************** + * GetCodeInfo (KERNEL.104) + */ +BOOL16 WINAPI GetCodeInfo16( FARPROC16 proc, SEGINFO *segInfo ) +{ + NE_MODULE *pModule; + SEGTABLEENTRY *pSeg; + int segNr; + + if ( !TASK_GetCodeSegment( proc, &pModule, &pSeg, &segNr ) ) + return FALSE; + + /* Fill in segment information */ + + segInfo->offSegment = pSeg->filepos; + segInfo->cbSegment = pSeg->size; + segInfo->flags = pSeg->flags; + segInfo->cbAlloc = pSeg->minsize; + segInfo->h = pSeg->hSeg; + segInfo->alignShift = pModule->alignment; + + if ( segNr == pModule->dgroup ) + segInfo->cbAlloc += pModule->heap_size + pModule->stack_size; + + /* Return module handle in %es */ + + CURRENT_STACK16->es = GlobalHandleToSel16( pModule->self ); + + return TRUE; +} + + +/********************************************************************** + * DefineHandleTable (KERNEL.94) + */ +BOOL16 WINAPI DefineHandleTable16( WORD wOffset ) +{ + FIXME("(%04x): stub ?\n", wOffset); + return TRUE; +} + + +/*********************************************************************** + * SetTaskQueue (KERNEL.34) + */ +HQUEUE16 WINAPI SetTaskQueue16( HTASK16 hTask, HQUEUE16 hQueue ) +{ + HQUEUE16 hPrev; + TDB *pTask; + + if (!hTask) hTask = GetCurrentTask(); + if (!(pTask = TASK_GetPtr( hTask ))) return 0; + + hPrev = pTask->hQueue; + pTask->hQueue = hQueue; + + return hPrev; +} + + +/*********************************************************************** + * GetTaskQueue (KERNEL.35) + */ +HQUEUE16 WINAPI GetTaskQueue16( HTASK16 hTask ) +{ + TDB *pTask; + + if (!hTask) hTask = GetCurrentTask(); + if (!(pTask = TASK_GetPtr( hTask ))) return 0; + return pTask->hQueue; +} + +/*********************************************************************** + * SetThreadQueue (KERNEL.463) + */ +HQUEUE16 WINAPI SetThreadQueue16( DWORD thread, HQUEUE16 hQueue ) +{ + HQUEUE16 oldQueue = NtCurrentTeb()->queue; + + if (thread && thread != GetCurrentThreadId()) + { + FIXME( "not supported on other thread %04lx\n", thread ); + return 0; + } + NtCurrentTeb()->queue = hQueue; + if ( GetTaskQueue16( NtCurrentTeb()->htask16 ) == oldQueue ) + SetTaskQueue16( NtCurrentTeb()->htask16, hQueue ); + return oldQueue; +} + +/*********************************************************************** + * GetThreadQueue (KERNEL.464) + */ +HQUEUE16 WINAPI GetThreadQueue16( DWORD thread ) +{ + if (thread && thread != GetCurrentThreadId()) + { + FIXME( "not supported on other thread %04lx\n", thread ); + return 0; + } + return NtCurrentTeb()->queue; +} + +/*********************************************************************** + * SetFastQueue (KERNEL.624) + */ +VOID WINAPI SetFastQueue16( DWORD thread, HQUEUE16 hQueue ) +{ + if (!thread || thread == GetCurrentThreadId()) + NtCurrentTeb()->queue = hQueue; + else + FIXME( "not supported on other thread %04lx\n", thread ); +} + +/*********************************************************************** + * GetFastQueue (KERNEL.625) + */ +HQUEUE16 WINAPI GetFastQueue16( void ) +{ + HQUEUE16 ret = NtCurrentTeb()->queue; + + if (!ret) FIXME("(): should initialize thread-local queue, expect failure!\n" ); + return ret; +} + +/*********************************************************************** + * SwitchStackTo (KERNEL.108) + */ +void WINAPI SwitchStackTo16( WORD seg, WORD ptr, WORD top ) +{ + TDB *pTask; + STACK16FRAME *oldFrame, *newFrame; + INSTANCEDATA *pData; + UINT16 copySize; + + if (!(pTask = TASK_GetCurrent())) return; + if (!(pData = (INSTANCEDATA *)GlobalLock16( seg ))) return; + TRACE("old=%04x:%04x new=%04x:%04x\n", + SELECTOROF( pTask->teb->cur_stack ), + OFFSETOF( pTask->teb->cur_stack ), seg, ptr ); + + /* Save the old stack */ + + oldFrame = THREAD_STACK16( pTask->teb ); + /* pop frame + args and push bp */ + pData->old_ss_sp = pTask->teb->cur_stack + sizeof(STACK16FRAME) + + 2 * sizeof(WORD); + *(WORD *)MapSL(pData->old_ss_sp) = oldFrame->bp; + pData->stacktop = top; + pData->stackmin = ptr; + pData->stackbottom = ptr; + + /* Switch to the new stack */ + + /* Note: we need to take the 3 arguments into account; otherwise, + * the stack will underflow upon return from this function. + */ + copySize = oldFrame->bp - OFFSETOF(pData->old_ss_sp); + copySize += 3 * sizeof(WORD) + sizeof(STACK16FRAME); + pTask->teb->cur_stack = MAKESEGPTR( seg, ptr - copySize ); + newFrame = THREAD_STACK16( pTask->teb ); + + /* Copy the stack frame and the local variables to the new stack */ + + memmove( newFrame, oldFrame, copySize ); + newFrame->bp = ptr; + *(WORD *)MapSL( MAKESEGPTR( seg, ptr ) ) = 0; /* clear previous bp */ +} + + +/*********************************************************************** + * SwitchStackBack (KERNEL.109) + */ +void WINAPI SwitchStackBack16( CONTEXT86 *context ) +{ + STACK16FRAME *oldFrame, *newFrame; + INSTANCEDATA *pData; + + if (!(pData = (INSTANCEDATA *)GlobalLock16(SELECTOROF(NtCurrentTeb()->cur_stack)))) + return; + if (!pData->old_ss_sp) + { + WARN("No previous SwitchStackTo\n" ); + return; + } + TRACE("restoring stack %04x:%04x\n", + SELECTOROF(pData->old_ss_sp), OFFSETOF(pData->old_ss_sp) ); + + oldFrame = CURRENT_STACK16; + + /* Pop bp from the previous stack */ + + context->Ebp = (context->Ebp & ~0xffff) | *(WORD *)MapSL(pData->old_ss_sp); + pData->old_ss_sp += sizeof(WORD); + + /* Switch back to the old stack */ + + NtCurrentTeb()->cur_stack = pData->old_ss_sp - sizeof(STACK16FRAME); + context->SegSs = SELECTOROF(pData->old_ss_sp); + context->Esp = OFFSETOF(pData->old_ss_sp) - sizeof(DWORD); /*ret addr*/ + pData->old_ss_sp = 0; + + /* Build a stack frame for the return */ + + newFrame = CURRENT_STACK16; + newFrame->frame32 = oldFrame->frame32; + newFrame->module_cs = oldFrame->module_cs; + newFrame->callfrom_ip = oldFrame->callfrom_ip; + newFrame->entry_ip = oldFrame->entry_ip; +} + + +/*********************************************************************** + * GetTaskQueueDS (KERNEL.118) + */ +void WINAPI GetTaskQueueDS16(void) +{ + CURRENT_STACK16->ds = GlobalHandleToSel16( GetTaskQueue16(0) ); +} + + +/*********************************************************************** + * GetTaskQueueES (KERNEL.119) + */ +void WINAPI GetTaskQueueES16(void) +{ + CURRENT_STACK16->es = GlobalHandleToSel16( GetTaskQueue16(0) ); +} + + +/*********************************************************************** + * GetCurrentTask (KERNEL32.@) + */ +HTASK16 WINAPI GetCurrentTask(void) +{ + return NtCurrentTeb()->htask16; +} + +/*********************************************************************** + * GetCurrentTask (KERNEL.36) + */ +DWORD WINAPI WIN16_GetCurrentTask(void) +{ + /* This is the version used by relay code; the first task is */ + /* returned in the high word of the result */ + return MAKELONG( GetCurrentTask(), hFirstTask ); +} + + +/*********************************************************************** + * GetCurrentPDB (KERNEL.37) + * + * UNDOC: returns PSP of KERNEL in high word + */ +DWORD WINAPI GetCurrentPDB16(void) +{ + TDB *pTask; + + if (!(pTask = TASK_GetCurrent())) return 0; + return MAKELONG(pTask->hPDB, 0); /* FIXME */ +} + + +/*********************************************************************** + * GetCurPID (KERNEL.157) + */ +DWORD WINAPI GetCurPID16( DWORD unused ) +{ + return 0; +} + + +/*********************************************************************** + * GetInstanceData (KERNEL.54) + */ +INT16 WINAPI GetInstanceData16( HINSTANCE16 instance, WORD buffer, INT16 len ) +{ + char *ptr = (char *)GlobalLock16( instance ); + if (!ptr || !len) return 0; + if ((int)buffer + len >= 0x10000) len = 0x10000 - buffer; + memcpy( (char *)GlobalLock16(CURRENT_DS) + buffer, ptr + buffer, len ); + return len; +} + + +/*********************************************************************** + * GetExeVersion (KERNEL.105) + */ +WORD WINAPI GetExeVersion16(void) +{ + TDB *pTask; + + if (!(pTask = TASK_GetCurrent())) return 0; + return pTask->version; +} + + +/*********************************************************************** + * SetErrorMode (KERNEL.107) + */ +UINT16 WINAPI SetErrorMode16( UINT16 mode ) +{ + TDB *pTask; + if (!(pTask = TASK_GetCurrent())) return 0; + pTask->error_mode = mode; + return SetErrorMode( mode ); +} + + +/*********************************************************************** + * GetNumTasks (KERNEL.152) + */ +UINT16 WINAPI GetNumTasks16(void) +{ + return nTaskCount; +} + + +/*********************************************************************** + * GetTaskDS (KERNEL.155) + * + * Note: this function apparently returns a DWORD with LOWORD == HIWORD. + * I don't think we need to bother with this. + */ +HINSTANCE16 WINAPI GetTaskDS16(void) +{ + TDB *pTask; + + if (!(pTask = TASK_GetCurrent())) return 0; + return GlobalHandleToSel16(pTask->hInstance); +} + +/*********************************************************************** + * GetDummyModuleHandleDS (KERNEL.602) + */ +WORD WINAPI GetDummyModuleHandleDS16(void) +{ + TDB *pTask; + WORD selector; + + if (!(pTask = TASK_GetCurrent())) return 0; + if (!(pTask->flags & TDBF_WIN32)) return 0; + selector = GlobalHandleToSel16( pTask->hModule ); + CURRENT_DS = selector; + return selector; +} + +/*********************************************************************** + * IsTask (KERNEL.320) + */ +BOOL16 WINAPI IsTask16( HTASK16 hTask ) +{ + TDB *pTask; + + if (!(pTask = TASK_GetPtr( hTask ))) return FALSE; + if (GlobalSize16( hTask ) < sizeof(TDB)) return FALSE; + return (pTask->magic == TDB_MAGIC); +} + + +/*********************************************************************** + * IsWinOldApTask (KERNEL.158) + */ +BOOL16 WINAPI IsWinOldApTask16( HTASK16 hTask ) +{ + /* should return bit 0 of byte 0x48 in PSP */ + return FALSE; +} + +/*********************************************************************** + * SetTaskSignalProc (KERNEL.38) + */ +FARPROC16 WINAPI SetTaskSignalProc( HTASK16 hTask, FARPROC16 proc ) +{ + TDB *pTask; + FARPROC16 oldProc; + + if (!hTask) hTask = GetCurrentTask(); + if (!(pTask = TASK_GetPtr( hTask ))) return NULL; + oldProc = pTask->userhandler; + pTask->userhandler = proc; + return oldProc; +} + +/*********************************************************************** + * SetSigHandler (KERNEL.140) + */ +WORD WINAPI SetSigHandler16( FARPROC16 newhandler, FARPROC16* oldhandler, + UINT16 *oldmode, UINT16 newmode, UINT16 flag ) +{ + FIXME("(%p,%p,%p,%d,%d), unimplemented.\n", + newhandler,oldhandler,oldmode,newmode,flag ); + + if (flag != 1) return 0; + if (!newmode) newhandler = NULL; /* Default handler */ + if (newmode != 4) + { + TDB *pTask; + + if (!(pTask = TASK_GetCurrent())) return 0; + if (oldmode) *oldmode = pTask->signal_flags; + pTask->signal_flags = newmode; + if (oldhandler) *oldhandler = pTask->sighandler; + pTask->sighandler = newhandler; + } + return 0; +} + + +/*********************************************************************** + * GlobalNotify (KERNEL.154) + * + * Note that GlobalNotify does _not_ return the old NotifyProc + * -- contrary to LocalNotify !! + */ +VOID WINAPI GlobalNotify16( FARPROC16 proc ) +{ + TDB *pTask; + + if (!(pTask = TASK_GetCurrent())) return; + pTask->discardhandler = proc; +} + + +/*********************************************************************** + * GetExePtrHelper + */ +static inline HMODULE16 GetExePtrHelper( HANDLE16 handle, HTASK16 *hTask ) +{ + char *ptr; + HANDLE16 owner; + + /* Check for module handle */ + + if (!(ptr = GlobalLock16( handle ))) return 0; + if (((NE_MODULE *)ptr)->magic == IMAGE_OS2_SIGNATURE) return handle; + + /* Search for this handle inside all tasks */ + + *hTask = hFirstTask; + while (*hTask) + { + TDB *pTask = TASK_GetPtr( *hTask ); + if ((*hTask == handle) || + (pTask->hInstance == handle) || + (pTask->hQueue == handle) || + (pTask->hPDB == handle)) return pTask->hModule; + *hTask = pTask->hNext; + } + + /* Check the owner for module handle */ + + owner = FarGetOwner16( handle ); + if (!(ptr = GlobalLock16( owner ))) return 0; + if (((NE_MODULE *)ptr)->magic == IMAGE_OS2_SIGNATURE) return owner; + + /* Search for the owner inside all tasks */ + + *hTask = hFirstTask; + while (*hTask) + { + TDB *pTask = TASK_GetPtr( *hTask ); + if ((*hTask == owner) || + (pTask->hInstance == owner) || + (pTask->hQueue == owner) || + (pTask->hPDB == owner)) return pTask->hModule; + *hTask = pTask->hNext; + } + + return 0; +} + +/*********************************************************************** + * GetExePtr (KERNEL.133) + */ +HMODULE16 WINAPI WIN16_GetExePtr( HANDLE16 handle ) +{ + HTASK16 hTask = 0; + HMODULE16 hModule = GetExePtrHelper( handle, &hTask ); + STACK16FRAME *frame = CURRENT_STACK16; + frame->ecx = hModule; + if (hTask) frame->es = hTask; + return hModule; +} + + +/*********************************************************************** + * K228 (KERNEL.228) + */ +HMODULE16 WINAPI GetExePtr( HANDLE16 handle ) +{ + HTASK16 hTask = 0; + return GetExePtrHelper( handle, &hTask ); +} + + +/*********************************************************************** + * TaskFirst (TOOLHELP.63) + */ +BOOL16 WINAPI TaskFirst16( TASKENTRY *lpte ) +{ + lpte->hNext = hFirstTask; + return TaskNext16( lpte ); +} + + +/*********************************************************************** + * TaskNext (TOOLHELP.64) + */ +BOOL16 WINAPI TaskNext16( TASKENTRY *lpte ) +{ + TDB *pTask; + INSTANCEDATA *pInstData; + + TRACE_(toolhelp)("(%p): task=%04x\n", lpte, lpte->hNext ); + if (!lpte->hNext) return FALSE; + + /* make sure that task and hInstance are valid (skip initial Wine task !) */ + while (1) { + pTask = TASK_GetPtr( lpte->hNext ); + if (!pTask || pTask->magic != TDB_MAGIC) return FALSE; + if (pTask->hInstance) + break; + lpte->hNext = pTask->hNext; + } + pInstData = MapSL( MAKESEGPTR( GlobalHandleToSel16(pTask->hInstance), 0 ) ); + lpte->hTask = lpte->hNext; + lpte->hTaskParent = pTask->hParent; + lpte->hInst = pTask->hInstance; + lpte->hModule = pTask->hModule; + lpte->wSS = SELECTOROF( pTask->teb->cur_stack ); + lpte->wSP = OFFSETOF( pTask->teb->cur_stack ); + lpte->wStackTop = pInstData->stacktop; + lpte->wStackMinimum = pInstData->stackmin; + lpte->wStackBottom = pInstData->stackbottom; + lpte->wcEvents = pTask->nEvents; + lpte->hQueue = pTask->hQueue; + lstrcpynA( lpte->szModule, pTask->module_name, sizeof(lpte->szModule) ); + lpte->wPSPOffset = 0x100; /*??*/ + lpte->hNext = pTask->hNext; + return TRUE; +} + + +/*********************************************************************** + * TaskFindHandle (TOOLHELP.65) + */ +BOOL16 WINAPI TaskFindHandle16( TASKENTRY *lpte, HTASK16 hTask ) +{ + lpte->hNext = hTask; + return TaskNext16( lpte ); +} + + +typedef INT (WINAPI *MessageBoxA_funcptr)(HWND hWnd, LPCSTR text, LPCSTR title, UINT type); + +/************************************************************************** + * FatalAppExit (KERNEL.137) + */ +void WINAPI FatalAppExit16( UINT16 action, LPCSTR str ) +{ + TDB *pTask = TASK_GetCurrent(); + + if (!pTask || !(pTask->error_mode & SEM_NOGPFAULTERRORBOX)) + { + HMODULE mod = GetModuleHandleA( "user32.dll" ); + if (mod) + { + MessageBoxA_funcptr pMessageBoxA = (MessageBoxA_funcptr)GetProcAddress( mod, "MessageBoxA" ); + if (pMessageBoxA) + { + pMessageBoxA( 0, str, NULL, MB_SYSTEMMODAL | MB_OK ); + goto done; + } + } + ERR( "%s\n", debugstr_a(str) ); + } + done: + ExitThread(0xff); +} + + +/*********************************************************************** + * TerminateApp (TOOLHELP.77) + * + * See "Undocumented Windows". + */ +void WINAPI TerminateApp16(HTASK16 hTask, WORD wFlags) +{ + if (hTask && hTask != GetCurrentTask()) + { + FIXME("cannot terminate task %x\n", hTask); + return; + } + + if (wFlags & NO_UAE_BOX) + { + UINT16 old_mode; + old_mode = SetErrorMode16(0); + SetErrorMode16(old_mode|SEM_NOGPFAULTERRORBOX); + } + FatalAppExit16( 0, NULL ); + + /* hmm, we're still alive ?? */ + + /* check undocumented flag */ + if (!(wFlags & 0x8000)) + TASK_CallTaskSignalProc( USIG16_TERMINATION, hTask ); + + /* UndocWin says to call int 0x21/0x4c exit=0xff here, + but let's just call ExitThread */ + ExitThread(0xff); +} + + +/*********************************************************************** + * GetAppCompatFlags (KERNEL.354) + */ +DWORD WINAPI GetAppCompatFlags16( HTASK16 hTask ) +{ + TDB *pTask; + + if (!hTask) hTask = GetCurrentTask(); + if (!(pTask=TASK_GetPtr( hTask ))) return 0; + if (GlobalSize16(hTask) < sizeof(TDB)) return 0; + return pTask->compat_flags; +} diff --git a/dlls/kernel/thunk.c b/dlls/kernel/thunk.c index 7dcb8f81871..019dc9ff50c 100644 --- a/dlls/kernel/thunk.c +++ b/dlls/kernel/thunk.c @@ -1589,7 +1589,7 @@ FARPROC THUNK_AllocLSThunklet( SEGPTR target, DWORD relay, THUNKLET_TYPE_LS ); if (!thunk) { - TDB *pTask = TASK_GetPtr( owner ); + TDB *pTask = GlobalLock16( owner ); if (!ThunkletHeap) THUNK_Init(); if ( !(thunk = HeapAlloc( ThunkletHeap, 0, sizeof(THUNKLET) )) ) @@ -1623,7 +1623,7 @@ SEGPTR THUNK_AllocSLThunklet( FARPROC target, DWORD relay, THUNKLET_TYPE_SL ); if (!thunk) { - TDB *pTask = TASK_GetPtr( owner ); + TDB *pTask = GlobalLock16( owner ); if (!ThunkletHeap) THUNK_Init(); if ( !(thunk = HeapAlloc( ThunkletHeap, 0, sizeof(THUNKLET) )) ) diff --git a/dlls/kernel/wowthunk.c b/dlls/kernel/wowthunk.c index 82073861601..30029b16086 100644 --- a/dlls/kernel/wowthunk.c +++ b/dlls/kernel/wowthunk.c @@ -235,7 +235,7 @@ HANDLE WINAPI K32WOWHandle32( WORD handle, WOW_HANDLE_TYPE type ) return (HANDLE)(ULONG_PTR)handle; case WOW_TYPE_HTASK: - return (HANDLE)TASK_GetPtr(handle)->teb->tid; + return (HANDLE)((TDB *)GlobalLock16(handle))->teb->tid; case WOW_TYPE_FULLHWND: FIXME( "conversion of full window handles not supported yet\n" ); @@ -276,7 +276,7 @@ WORD WINAPI K32WOWHandle16( HANDLE handle, WOW_HANDLE_TYPE type ) return LOWORD(handle); case WOW_TYPE_HTASK: - return THREAD_IdToTEB((DWORD)handle)->htask16; + return TASK_GetTaskFromThread( (DWORD)handle ); default: ERR( "handle %p of unknown type %d\n", handle, type ); diff --git a/dlls/ntdll/Makefile.in b/dlls/ntdll/Makefile.in index 78909569a60..fe92065eb2f 100644 --- a/dlls/ntdll/Makefile.in +++ b/dlls/ntdll/Makefile.in @@ -21,7 +21,6 @@ C_SRCS = \ $(TOPOBJDIR)/loader/pe_image.c \ $(TOPOBJDIR)/loader/task.c \ $(TOPOBJDIR)/loader/ne/module.c \ - $(TOPOBJDIR)/loader/ne/segment.c \ $(TOPOBJDIR)/memory/codepage.c \ $(TOPOBJDIR)/memory/environ.c \ $(TOPOBJDIR)/memory/global.c \ @@ -89,7 +88,7 @@ ASM_SRCS = \ relay16.s \ relay32.s -EXTRA_OBJS = $(ASM_SRCS:.s=.o) $(MODULE).glue.o +EXTRA_OBJS = $(ASM_SRCS:.s=.o) SUBDIRS = tests diff --git a/files/drive.c b/files/drive.c index bf29d75c6f8..4cdf3853b18 100644 --- a/files/drive.c +++ b/files/drive.c @@ -428,7 +428,7 @@ int DRIVE_IsValid( int drive ) */ int DRIVE_GetCurrentDrive(void) { - TDB *pTask = TASK_GetCurrent(); + TDB *pTask = GlobalLock16(GetCurrentTask()); if (pTask && (pTask->curdrive & 0x80)) return pTask->curdrive & ~0x80; return DRIVE_CurDrive; } @@ -439,7 +439,7 @@ int DRIVE_GetCurrentDrive(void) */ int DRIVE_SetCurrentDrive( int drive ) { - TDB *pTask = TASK_GetCurrent(); + TDB *pTask = GlobalLock16(GetCurrentTask()); if (!DRIVE_IsValid( drive )) { SetLastError( ERROR_INVALID_DRIVE ); @@ -619,7 +619,7 @@ const char * DRIVE_GetRoot( int drive ) */ LPCWSTR DRIVE_GetDosCwd( int drive ) { - TDB *pTask = TASK_GetCurrent(); + TDB *pTask = GlobalLock16(GetCurrentTask()); if (!DRIVE_IsValid( drive )) return NULL; /* Check if we need to change the directory to the new task. */ @@ -643,7 +643,7 @@ LPCWSTR DRIVE_GetDosCwd( int drive ) */ const char * DRIVE_GetUnixCwd( int drive ) { - TDB *pTask = TASK_GetCurrent(); + TDB *pTask = GlobalLock16(GetCurrentTask()); if (!DRIVE_IsValid( drive )) return NULL; /* Check if we need to change the directory to the new task. */ @@ -1234,7 +1234,7 @@ int DRIVE_Chdir( int drive, LPCWSTR path ) WCHAR buffer[MAX_PATHNAME_LEN]; LPSTR unix_cwd; BY_HANDLE_FILE_INFORMATION info; - TDB *pTask = TASK_GetCurrent(); + TDB *pTask = GlobalLock16(GetCurrentTask()); buffer[0] = 'A' + drive; buffer[1] = ':'; diff --git a/include/task.h b/include/task.h index a4fc2007282..b4cdf2d8552 100644 --- a/include/task.h +++ b/include/task.h @@ -163,10 +163,8 @@ extern void TASK_CreateMainTask(void); extern HTASK16 TASK_SpawnTask( struct _NE_MODULE *pModule, WORD cmdShow, LPCSTR cmdline, BYTE len, HANDLE *hThread ); extern void TASK_ExitTask(void); -extern HTASK16 TASK_GetNextTask( HTASK16 hTask ); -extern TDB *TASK_GetPtr( HTASK16 hTask ); +extern HTASK16 TASK_GetTaskFromThread( DWORD thread ); extern TDB *TASK_GetCurrent(void); extern void TASK_InstallTHHook( THHOOK *pNewThook ); -extern void TASK_CallTaskSignalProc( UINT16 uCode, HANDLE16 hTaskOrModule ); #endif /* __WINE_TASK_H */ diff --git a/include/thread.h b/include/thread.h index 79665cb3af6..bd9a9ccf749 100644 --- a/include/thread.h +++ b/include/thread.h @@ -149,7 +149,6 @@ typedef struct _TEB /* scheduler/thread.c */ extern void THREAD_Init(void); extern TEB *THREAD_InitStack( TEB *teb, DWORD stack_size ); -extern TEB *THREAD_IdToTEB( DWORD id ); /* scheduler/sysdeps.c */ extern int SYSDEPS_SpawnThread( void (*func)(TEB *), TEB *teb ); diff --git a/loader/module.c b/loader/module.c index f75ce9fe1e9..e18db677b5e 100644 --- a/loader/module.c +++ b/loader/module.c @@ -781,27 +781,6 @@ VOID WINAPI FreeLibraryAndExitThread(HINSTANCE hLibModule, DWORD dwExitCode) ExitThread(dwExitCode); } -/*********************************************************************** - * PrivateLoadLibrary (KERNEL32.@) - * - * FIXME: rough guesswork, don't know what "Private" means - */ -HINSTANCE16 WINAPI PrivateLoadLibrary(LPCSTR libname) -{ - return LoadLibrary16(libname); -} - -/*********************************************************************** - * PrivateFreeLibrary (KERNEL32.@) - * - * FIXME: rough guesswork, don't know what "Private" means - */ -void WINAPI PrivateFreeLibrary(HINSTANCE16 handle) -{ - FreeLibrary16(handle); -} - - /*********************************************************************** * GetProcAddress (KERNEL32.@) */ diff --git a/loader/ne/module.c b/loader/ne/module.c index 0e65b946d15..4713bf41716 100644 --- a/loader/ne/module.c +++ b/loader/ne/module.c @@ -59,41 +59,8 @@ typedef struct _GPHANDLERDEF } GPHANDLERDEF; #include "poppack.h" -/* - * Segment table entry - */ -struct ne_segment_table_entry_s -{ - WORD seg_data_offset; /* Sector offset of segment data */ - WORD seg_data_length; /* Length of segment data */ - WORD seg_flags; /* Flags associated with this segment */ - WORD min_alloc; /* Minimum allocation size for this */ -}; - #define hFirstModule (pThhook->hExeHead) -static NE_MODULE *pCachedModule = 0; /* Module cached by NE_OpenFile */ - -static HINSTANCE16 NE_LoadModule( LPCSTR name, BOOL lib_only ); -static BOOL16 NE_FreeModule( HMODULE16 hModule, BOOL call_wep ); - -static HINSTANCE16 MODULE_LoadModule16( LPCSTR libname, BOOL implicit, BOOL lib_only ); - -static HMODULE16 NE_GetModuleByFilename( LPCSTR name ); - -/* ### start build ### */ -extern WORD CALLBACK NE_CallTo16_word_w(FARPROC16,WORD); -/* ### stop build ### */ - - -static WINE_EXCEPTION_FILTER(page_fault) -{ - if (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION || - GetExceptionCode() == EXCEPTION_PRIV_INSTRUCTION) - return EXCEPTION_EXECUTE_HANDLER; - return EXCEPTION_CONTINUE_SEARCH; -} - /*********************************************************************** * NE_GetPtr @@ -104,160 +71,6 @@ NE_MODULE *NE_GetPtr( HMODULE16 hModule ) } -/*********************************************************************** - * NE_DumpModule - */ -void NE_DumpModule( HMODULE16 hModule ) -{ - int i, ordinal; - SEGTABLEENTRY *pSeg; - BYTE *pstr; - WORD *pword; - NE_MODULE *pModule; - ET_BUNDLE *bundle; - ET_ENTRY *entry; - - if (!(pModule = NE_GetPtr( hModule ))) - { - MESSAGE( "**** %04x is not a module handle\n", hModule ); - return; - } - - /* Dump the module info */ - DPRINTF( "---\n" ); - DPRINTF( "Module %04x:\n", hModule ); - DPRINTF( "count=%d flags=%04x heap=%d stack=%d\n", - pModule->count, pModule->flags, - pModule->heap_size, pModule->stack_size ); - DPRINTF( "cs:ip=%04x:%04x ss:sp=%04x:%04x ds=%04x nb seg=%d modrefs=%d\n", - pModule->cs, pModule->ip, pModule->ss, pModule->sp, pModule->dgroup, - pModule->seg_count, pModule->modref_count ); - DPRINTF( "os_flags=%d swap_area=%d version=%04x\n", - pModule->os_flags, pModule->min_swap_area, - pModule->expected_version ); - if (pModule->flags & NE_FFLAGS_WIN32) - DPRINTF( "PE module=%p\n", pModule->module32 ); - - /* Dump the file info */ - DPRINTF( "---\n" ); - DPRINTF( "Filename: '%s'\n", NE_MODULE_NAME(pModule) ); - - /* Dump the segment table */ - DPRINTF( "---\n" ); - DPRINTF( "Segment table:\n" ); - pSeg = NE_SEG_TABLE( pModule ); - for (i = 0; i < pModule->seg_count; i++, pSeg++) - DPRINTF( "%02x: pos=%d size=%d flags=%04x minsize=%d hSeg=%04x\n", - i + 1, pSeg->filepos, pSeg->size, pSeg->flags, - pSeg->minsize, pSeg->hSeg ); - - /* Dump the resource table */ - DPRINTF( "---\n" ); - DPRINTF( "Resource table:\n" ); - if (pModule->res_table) - { - pword = (WORD *)((BYTE *)pModule + pModule->res_table); - DPRINTF( "Alignment: %d\n", *pword++ ); - while (*pword) - { - NE_TYPEINFO *ptr = (NE_TYPEINFO *)pword; - NE_NAMEINFO *pname = (NE_NAMEINFO *)(ptr + 1); - DPRINTF( "id=%04x count=%d\n", ptr->type_id, ptr->count ); - for (i = 0; i < ptr->count; i++, pname++) - DPRINTF( "offset=%d len=%d id=%04x\n", - pname->offset, pname->length, pname->id ); - pword = (WORD *)pname; - } - } - else DPRINTF( "None\n" ); - - /* Dump the resident name table */ - DPRINTF( "---\n" ); - DPRINTF( "Resident-name table:\n" ); - pstr = (char *)pModule + pModule->name_table; - while (*pstr) - { - DPRINTF( "%*.*s: %d\n", *pstr, *pstr, pstr + 1, - *(WORD *)(pstr + *pstr + 1) ); - pstr += *pstr + 1 + sizeof(WORD); - } - - /* Dump the module reference table */ - DPRINTF( "---\n" ); - DPRINTF( "Module ref table:\n" ); - if (pModule->modref_table) - { - pword = (WORD *)((BYTE *)pModule + pModule->modref_table); - for (i = 0; i < pModule->modref_count; i++, pword++) - { - char name[10]; - GetModuleName16( *pword, name, sizeof(name) ); - DPRINTF( "%d: %04x -> '%s'\n", i, *pword, name ); - } - } - else DPRINTF( "None\n" ); - - /* Dump the entry table */ - DPRINTF( "---\n" ); - DPRINTF( "Entry table:\n" ); - bundle = (ET_BUNDLE *)((BYTE *)pModule+pModule->entry_table); - do { - entry = (ET_ENTRY *)((BYTE *)bundle+6); - DPRINTF( "Bundle %d-%d: %02x\n", bundle->first, bundle->last, entry->type); - ordinal = bundle->first; - while (ordinal < bundle->last) - { - if (entry->type == 0xff) - DPRINTF("%d: %02x:%04x (moveable)\n", ordinal++, entry->segnum, entry->offs); - else - DPRINTF("%d: %02x:%04x (fixed)\n", ordinal++, entry->segnum, entry->offs); - entry++; - } - } while ( (bundle->next) - && (bundle = ((ET_BUNDLE *)((BYTE *)pModule + bundle->next))) ); - - /* Dump the non-resident names table */ - DPRINTF( "---\n" ); - DPRINTF( "Non-resident names table:\n" ); - if (pModule->nrname_handle) - { - pstr = (char *)GlobalLock16( pModule->nrname_handle ); - while (*pstr) - { - DPRINTF( "%*.*s: %d\n", *pstr, *pstr, pstr + 1, - *(WORD *)(pstr + *pstr + 1) ); - pstr += *pstr + 1 + sizeof(WORD); - } - } - DPRINTF( "\n" ); -} - - -/*********************************************************************** - * NE_WalkModules - * - * Walk the module list and print the modules. - */ -void NE_WalkModules(void) -{ - HMODULE16 hModule = hFirstModule; - MESSAGE( "Module Flags Name\n" ); - while (hModule) - { - NE_MODULE *pModule = NE_GetPtr( hModule ); - if (!pModule) - { - MESSAGE( "Bad module %04x in list\n", hModule ); - return; - } - MESSAGE( " %04x %04x %.*s\n", hModule, pModule->flags, - *((char *)pModule + pModule->name_table), - (char *)pModule + pModule->name_table + 1 ); - hModule = pModule->next; - } -} - - /********************************************************************** * NE_RegisterModule */ @@ -357,18 +170,6 @@ WORD NE_GetOrdinal( HMODULE16 hModule, const char *name ) } -/*********************************************************************** - * EntryAddrProc (KERNEL.667) Wine-specific export - * - * Return the entry point for a given ordinal. - */ -FARPROC16 WINAPI EntryAddrProc16( HMODULE16 hModule, WORD ordinal ) -{ - FARPROC16 ret = NE_GetEntryPointEx( hModule, ordinal, TRUE ); - CURRENT_STACK16->ecx = hModule; /* FIXME: might be incorrect value */ - return ret; -} - /*********************************************************************** * NE_GetEntryPoint */ @@ -417,1000 +218,6 @@ FARPROC16 NE_GetEntryPointEx( HMODULE16 hModule, WORD ordinal, BOOL16 snoop ) } -/*********************************************************************** - * NE_SetEntryPoint - * - * Change the value of an entry point. Use with caution! - * It can only change the offset value, not the selector. - */ -BOOL16 NE_SetEntryPoint( HMODULE16 hModule, WORD ordinal, WORD offset ) -{ - NE_MODULE *pModule; - ET_ENTRY *entry; - ET_BUNDLE *bundle; - int i; - - if (!(pModule = NE_GetPtr( hModule ))) return FALSE; - assert( !(pModule->flags & NE_FFLAGS_WIN32) ); - - bundle = (ET_BUNDLE *)((BYTE *)pModule + pModule->entry_table); - while ((ordinal < bundle->first + 1) || (ordinal > bundle->last)) - { - bundle = (ET_BUNDLE *)((BYTE *)pModule + bundle->next); - if (!(bundle->next)) - return 0; - } - - entry = (ET_ENTRY *)((BYTE *)bundle+6); - for (i=0; i < (ordinal - bundle->first - 1); i++) - entry++; - - memcpy( &entry->offs, &offset, sizeof(WORD) ); - return TRUE; -} - - -/*********************************************************************** - * NE_OpenFile - */ -HANDLE NE_OpenFile( NE_MODULE *pModule ) -{ - HANDLE handle; - char *name; - - TRACE("(%p)\n", pModule ); - /* mjm - removed module caching because it keeps open file handles - thus preventing CDROMs from being ejected */ - name = NE_MODULE_NAME( pModule ); - if ((handle = CreateFileA( name, GENERIC_READ, FILE_SHARE_READ, - NULL, OPEN_EXISTING, 0, 0 )) == INVALID_HANDLE_VALUE) - MESSAGE( "Can't open file '%s' for module %04x\n", name, pModule->self ); - TRACE("opened '%s' -> %p\n", name, handle); - return handle; -} - - -/* wrapper for SetFilePointer and ReadFile */ -static BOOL read_data( HANDLE handle, LONG offset, void *buffer, DWORD size ) -{ - DWORD result; - - if (SetFilePointer( handle, offset, NULL, SEEK_SET ) == INVALID_SET_FILE_POINTER) return FALSE; - if (!ReadFile( handle, buffer, size, &result, NULL )) return FALSE; - return (result == size); -} - -/*********************************************************************** - * NE_LoadExeHeader - */ -static HMODULE16 NE_LoadExeHeader( HANDLE handle, LPCSTR path ) -{ - IMAGE_DOS_HEADER mz_header; - IMAGE_OS2_HEADER ne_header; - int size; - HMODULE16 hModule; - NE_MODULE *pModule; - BYTE *pData, *pTempEntryTable; - char *buffer, *fastload = NULL; - int fastload_offset = 0, fastload_length = 0; - ET_ENTRY *entry; - ET_BUNDLE *bundle, *oldbundle; - OFSTRUCT *ofs; - - /* Read a block from either the file or the fast-load area. */ -#define READ(offset,size,buffer) \ - ((fastload && ((offset) >= fastload_offset) && \ - ((offset)+(size) <= fastload_offset+fastload_length)) ? \ - (memcpy( buffer, fastload+(offset)-fastload_offset, (size) ), TRUE) : \ - read_data( handle, (offset), (buffer), (size))) - - if (!read_data( handle, 0, &mz_header, sizeof(mz_header)) || - (mz_header.e_magic != IMAGE_DOS_SIGNATURE)) - return (HMODULE16)11; /* invalid exe */ - - if (!read_data( handle, mz_header.e_lfanew, &ne_header, sizeof(ne_header) )) - return (HMODULE16)11; /* invalid exe */ - - if (ne_header.ne_magic == IMAGE_NT_SIGNATURE) return (HMODULE16)21; /* win32 exe */ - if (ne_header.ne_magic == IMAGE_OS2_SIGNATURE_LX) { - MESSAGE("Sorry, this is an OS/2 linear executable (LX) file !\n"); - return (HMODULE16)12; - } - if (ne_header.ne_magic != IMAGE_OS2_SIGNATURE) return (HMODULE16)11; /* invalid exe */ - - /* We now have a valid NE header */ - - size = sizeof(NE_MODULE) + - /* segment table */ - ne_header.ne_cseg * sizeof(SEGTABLEENTRY) + - /* resource table */ - ne_header.ne_restab - ne_header.ne_rsrctab + - /* resident names table */ - ne_header.ne_modtab - ne_header.ne_restab + - /* module ref table */ - ne_header.ne_cmod * sizeof(WORD) + - /* imported names table */ - ne_header.ne_enttab - ne_header.ne_imptab + - /* entry table length */ - ne_header.ne_cbenttab + - /* entry table extra conversion space */ - sizeof(ET_BUNDLE) + - 2 * (ne_header.ne_cbenttab - ne_header.ne_cmovent*6) + - /* loaded file info */ - sizeof(OFSTRUCT) - sizeof(ofs->szPathName) + strlen(path) + 1; - - hModule = GlobalAlloc16( GMEM_FIXED | GMEM_ZEROINIT, size ); - if (!hModule) return (HMODULE16)11; /* invalid exe */ - - FarSetOwner16( hModule, hModule ); - pModule = (NE_MODULE *)GlobalLock16( hModule ); - memcpy( pModule, &ne_header, sizeof(ne_header) ); - pModule->count = 0; - /* check *programs* for default minimal stack size */ - if ( (!(pModule->flags & NE_FFLAGS_LIBMODULE)) - && (pModule->stack_size < 0x1400) ) - pModule->stack_size = 0x1400; - pModule->module32 = 0; - pModule->self = hModule; - pModule->self_loading_sel = 0; - pData = (BYTE *)(pModule + 1); - - /* Clear internal Wine flags in case they are set in the EXE file */ - - pModule->flags &= ~(NE_FFLAGS_BUILTIN | NE_FFLAGS_WIN32); - - /* Read the fast-load area */ - - if (ne_header.ne_flagsothers & NE_AFLAGS_FASTLOAD) - { - fastload_offset=ne_header.ne_pretthunks << ne_header.ne_align; - fastload_length=ne_header.ne_psegrefbytes << ne_header.ne_align; - TRACE("Using fast-load area offset=%x len=%d\n", - fastload_offset, fastload_length ); - if ((fastload = HeapAlloc( GetProcessHeap(), 0, fastload_length )) != NULL) - { - if (!read_data( handle, fastload_offset, fastload, fastload_length)) - { - HeapFree( GetProcessHeap(), 0, fastload ); - WARN("Error reading fast-load area!\n"); - fastload = NULL; - } - } - } - - /* Get the segment table */ - - pModule->seg_table = pData - (BYTE *)pModule; - buffer = HeapAlloc( GetProcessHeap(), 0, ne_header.ne_cseg * - sizeof(struct ne_segment_table_entry_s)); - if (buffer) - { - int i; - struct ne_segment_table_entry_s *pSeg; - - if (!READ( mz_header.e_lfanew + ne_header.ne_segtab, - ne_header.ne_cseg * sizeof(struct ne_segment_table_entry_s), - buffer )) - { - HeapFree( GetProcessHeap(), 0, buffer ); - if (fastload) - HeapFree( GetProcessHeap(), 0, fastload ); - GlobalFree16( hModule ); - return (HMODULE16)11; /* invalid exe */ - } - pSeg = (struct ne_segment_table_entry_s *)buffer; - for (i = ne_header.ne_cseg; i > 0; i--, pSeg++) - { - memcpy( pData, pSeg, sizeof(*pSeg) ); - pData += sizeof(SEGTABLEENTRY); - } - HeapFree( GetProcessHeap(), 0, buffer ); - } - else - { - if (fastload) - HeapFree( GetProcessHeap(), 0, fastload ); - GlobalFree16( hModule ); - return (HMODULE16)11; /* invalid exe */ - } - - /* Get the resource table */ - - if (ne_header.ne_rsrctab < ne_header.ne_restab) - { - pModule->res_table = pData - (BYTE *)pModule; - if (!READ(mz_header.e_lfanew + ne_header.ne_rsrctab, - ne_header.ne_restab - ne_header.ne_rsrctab, - pData )) - return (HMODULE16)11; /* invalid exe */ - pData += ne_header.ne_restab - ne_header.ne_rsrctab; - NE_InitResourceHandler( pModule ); - } - else pModule->res_table = 0; /* No resource table */ - - /* Get the resident names table */ - - pModule->name_table = pData - (BYTE *)pModule; - if (!READ( mz_header.e_lfanew + ne_header.ne_restab, - ne_header.ne_modtab - ne_header.ne_restab, - pData )) - { - if (fastload) - HeapFree( GetProcessHeap(), 0, fastload ); - GlobalFree16( hModule ); - return (HMODULE16)11; /* invalid exe */ - } - pData += ne_header.ne_modtab - ne_header.ne_restab; - - /* Get the module references table */ - - if (ne_header.ne_cmod > 0) - { - pModule->modref_table = pData - (BYTE *)pModule; - if (!READ( mz_header.e_lfanew + ne_header.ne_modtab, - ne_header.ne_cmod * sizeof(WORD), - pData )) - { - if (fastload) - HeapFree( GetProcessHeap(), 0, fastload ); - GlobalFree16( hModule ); - return (HMODULE16)11; /* invalid exe */ - } - pData += ne_header.ne_cmod * sizeof(WORD); - } - else pModule->modref_table = 0; /* No module references */ - - /* Get the imported names table */ - - pModule->import_table = pData - (BYTE *)pModule; - if (!READ( mz_header.e_lfanew + ne_header.ne_imptab, - ne_header.ne_enttab - ne_header.ne_imptab, - pData )) - { - if (fastload) - HeapFree( GetProcessHeap(), 0, fastload ); - GlobalFree16( hModule ); - return (HMODULE16)11; /* invalid exe */ - } - pData += ne_header.ne_enttab - ne_header.ne_imptab; - - /* Load entry table, convert it to the optimized version used by Windows */ - - if ((pTempEntryTable = HeapAlloc( GetProcessHeap(), 0, ne_header.ne_cbenttab)) != NULL) - { - BYTE nr_entries, type, *s; - - TRACE("Converting entry table.\n"); - pModule->entry_table = pData - (BYTE *)pModule; - if (!READ( mz_header.e_lfanew + ne_header.ne_enttab, - ne_header.ne_cbenttab, pTempEntryTable )) - { - HeapFree( GetProcessHeap(), 0, pTempEntryTable ); - if (fastload) - HeapFree( GetProcessHeap(), 0, fastload ); - GlobalFree16( hModule ); - return (HMODULE16)11; /* invalid exe */ - } - - s = pTempEntryTable; - TRACE("entry table: offs %04x, len %04x, entries %d\n", ne_header.ne_enttab, ne_header.ne_cbenttab, *s); - - bundle = (ET_BUNDLE *)pData; - TRACE("first bundle: %p\n", bundle); - memset(bundle, 0, sizeof(ET_BUNDLE)); /* in case no entry table exists */ - entry = (ET_ENTRY *)((BYTE *)bundle+6); - - while ((nr_entries = *s++)) - { - if ((type = *s++)) - { - bundle->last += nr_entries; - if (type == 0xff) - while (nr_entries--) - { - entry->type = type; - entry->flags = *s++; - s += 2; - entry->segnum = *s++; - entry->offs = *(WORD *)s; s += 2; - /*TRACE(module, "entry: %p, type: %d, flags: %d, segnum: %d, offs: %04x\n", entry, entry->type, entry->flags, entry->segnum, entry->offs);*/ - entry++; - } - else - while (nr_entries--) - { - entry->type = type; - entry->flags = *s++; - entry->segnum = type; - entry->offs = *(WORD *)s; s += 2; - /*TRACE(module, "entry: %p, type: %d, flags: %d, segnum: %d, offs: %04x\n", entry, entry->type, entry->flags, entry->segnum, entry->offs);*/ - entry++; - } - } - else - { - if (bundle->first == bundle->last) - { - bundle->first += nr_entries; - bundle->last += nr_entries; - } - else - { - oldbundle = bundle; - oldbundle->next = ((int)entry - (int)pModule); - bundle = (ET_BUNDLE *)entry; - TRACE("new bundle: %p\n", bundle); - bundle->first = bundle->last = - oldbundle->last + nr_entries; - bundle->next = 0; - (BYTE *)entry += sizeof(ET_BUNDLE); - } - } - } - HeapFree( GetProcessHeap(), 0, pTempEntryTable ); - } - else - { - if (fastload) - HeapFree( GetProcessHeap(), 0, fastload ); - GlobalFree16( hModule ); - return (HMODULE16)11; /* invalid exe */ - } - - pData += ne_header.ne_cbenttab + sizeof(ET_BUNDLE) + - 2 * (ne_header.ne_cbenttab - ne_header.ne_cmovent*6); - - if ((DWORD)entry > (DWORD)pData) - ERR("converted entry table bigger than reserved space !!!\nentry: %p, pData: %p. Please report !\n", entry, pData); - - /* Store the filename information */ - - pModule->fileinfo = pData - (BYTE *)pModule; - size = sizeof(OFSTRUCT) - sizeof(ofs->szPathName) + strlen(path) + 1; - ofs = (OFSTRUCT *)pData; - ofs->cBytes = size - 1; - ofs->fFixedDisk = 1; - strcpy( ofs->szPathName, path ); - pData += size; - - /* Free the fast-load area */ - -#undef READ - if (fastload) - HeapFree( GetProcessHeap(), 0, fastload ); - - /* Get the non-resident names table */ - - if (ne_header.ne_cbnrestab) - { - pModule->nrname_handle = GlobalAlloc16( 0, ne_header.ne_cbnrestab ); - if (!pModule->nrname_handle) - { - GlobalFree16( hModule ); - return (HMODULE16)11; /* invalid exe */ - } - FarSetOwner16( pModule->nrname_handle, hModule ); - buffer = GlobalLock16( pModule->nrname_handle ); - if (!read_data( handle, ne_header.ne_nrestab, buffer, ne_header.ne_cbnrestab )) - { - GlobalFree16( pModule->nrname_handle ); - GlobalFree16( hModule ); - return (HMODULE16)11; /* invalid exe */ - } - } - else pModule->nrname_handle = 0; - - /* Allocate a segment for the implicitly-loaded DLLs */ - - if (pModule->modref_count) - { - pModule->dlls_to_init = GlobalAlloc16( GMEM_ZEROINIT, - (pModule->modref_count+1)*sizeof(HMODULE16) ); - if (!pModule->dlls_to_init) - { - if (pModule->nrname_handle) GlobalFree16( pModule->nrname_handle ); - GlobalFree16( hModule ); - return (HMODULE16)11; /* invalid exe */ - } - FarSetOwner16( pModule->dlls_to_init, hModule ); - } - else pModule->dlls_to_init = 0; - - NE_RegisterModule( pModule ); - SNOOP16_RegisterDLL(pModule,path); - return hModule; -} - - -/*********************************************************************** - * NE_LoadDLLs - * - * Load all DLLs implicitly linked to a module. - */ -static BOOL NE_LoadDLLs( NE_MODULE *pModule ) -{ - int i; - WORD *pModRef = (WORD *)((char *)pModule + pModule->modref_table); - WORD *pDLLs = (WORD *)GlobalLock16( pModule->dlls_to_init ); - - for (i = 0; i < pModule->modref_count; i++, pModRef++) - { - char buffer[260], *p; - BYTE *pstr = (BYTE *)pModule + pModule->import_table + *pModRef; - memcpy( buffer, pstr + 1, *pstr ); - *(buffer + *pstr) = 0; /* terminate it */ - - TRACE("Loading '%s'\n", buffer ); - if (!(*pModRef = GetModuleHandle16( buffer ))) - { - /* If the DLL is not loaded yet, load it and store */ - /* its handle in the list of DLLs to initialize. */ - HMODULE16 hDLL; - - /* Append .DLL to name if no extension present */ - if (!(p = strrchr( buffer, '.')) || strchr( p, '/' ) || strchr( p, '\\')) - strcat( buffer, ".DLL" ); - - if ((hDLL = MODULE_LoadModule16( buffer, TRUE, TRUE )) < 32) - { - /* FIXME: cleanup what was done */ - - MESSAGE( "Could not load '%s' required by '%.*s', error=%d\n", - buffer, *((BYTE*)pModule + pModule->name_table), - (char *)pModule + pModule->name_table + 1, hDLL ); - return FALSE; - } - *pModRef = GetExePtr( hDLL ); - *pDLLs++ = *pModRef; - } - else /* Increment the reference count of the DLL */ - { - NE_MODULE *pOldDLL; - - pOldDLL = NE_GetPtr( *pModRef ); - if (pOldDLL) pOldDLL->count++; - } - } - return TRUE; -} - - -/********************************************************************** - * NE_DoLoadModule - * - * Load first instance of NE module from file. - * - * pModule must point to a module structure prepared by NE_LoadExeHeader. - * This routine must never be called twice on a module. - * - */ -static HINSTANCE16 NE_DoLoadModule( NE_MODULE *pModule ) -{ - /* Allocate the segments for this module */ - - if (!NE_CreateAllSegments( pModule )) - return ERROR_NOT_ENOUGH_MEMORY; /* 8 */ - - /* Load the referenced DLLs */ - - if (!NE_LoadDLLs( pModule )) - return ERROR_FILE_NOT_FOUND; /* 2 */ - - /* Load the segments */ - - NE_LoadAllSegments( pModule ); - - /* Make sure the usage count is 1 on the first loading of */ - /* the module, even if it contains circular DLL references */ - - pModule->count = 1; - - return NE_GetInstance( pModule ); -} - -/********************************************************************** - * NE_LoadModule - * - * Load first instance of NE module. (Note: caller is responsible for - * ensuring the module isn't already loaded!) - * - * If the module turns out to be an executable module, only a - * handle to a module stub is returned; this needs to be initialized - * by calling NE_DoLoadModule later, in the context of the newly - * created process. - * - * If lib_only is TRUE, however, the module is perforce treated - * like a DLL module, even if it is an executable module. - * - */ -static HINSTANCE16 NE_LoadModule( LPCSTR name, BOOL lib_only ) -{ - NE_MODULE *pModule; - HMODULE16 hModule; - HINSTANCE16 hInstance; - HFILE16 hFile; - OFSTRUCT ofs; - - /* Open file */ - if ((hFile = OpenFile16( name, &ofs, OF_READ )) == HFILE_ERROR16) - return (HMODULE16)2; /* File not found */ - - hModule = NE_LoadExeHeader( DosFileHandleToWin32Handle(hFile), ofs.szPathName ); - _lclose16( hFile ); - if (hModule < 32) return hModule; - - pModule = NE_GetPtr( hModule ); - if ( !pModule ) return hModule; - - if ( !lib_only && !( pModule->flags & NE_FFLAGS_LIBMODULE ) ) - return hModule; - - hInstance = NE_DoLoadModule( pModule ); - if ( hInstance < 32 ) - { - /* cleanup ... */ - NE_FreeModule( hModule, 0 ); - } - - return hInstance; -} - - -/********************************************************************** - * MODULE_LoadModule16 - * - * Load a NE module in the order of the loadorder specification. - * The caller is responsible that the module is not loaded already. - * - */ -static HINSTANCE16 MODULE_LoadModule16( LPCSTR libname, BOOL implicit, BOOL lib_only ) -{ - HINSTANCE16 hinst = 2; - enum loadorder_type loadorder[LOADORDER_NTYPES]; - int i; - const char *filetype = ""; - - MODULE_GetLoadOrder(loadorder, libname, FALSE); - - for(i = 0; i < LOADORDER_NTYPES; i++) - { - if (loadorder[i] == LOADORDER_INVALID) break; - - switch(loadorder[i]) - { - case LOADORDER_DLL: - TRACE("Trying native dll '%s'\n", libname); - hinst = NE_LoadModule(libname, lib_only); - filetype = "native"; - break; - - case LOADORDER_BI: - TRACE("Trying built-in '%s'\n", libname); - hinst = BUILTIN_LoadModule(libname); - filetype = "builtin"; - break; - - default: - hinst = 2; - break; - } - - if(hinst >= 32) - { - TRACE_(loaddll)("Loaded module '%s' : %s\n", libname, filetype); - if(!implicit) - { - HMODULE16 hModule; - NE_MODULE *pModule; - - hModule = GetModuleHandle16(libname); - if(!hModule) - { - ERR("Serious trouble. Just loaded module '%s' (hinst=0x%04x), but can't get module handle. Filename too long ?\n", - libname, hinst); - return 6; /* ERROR_INVALID_HANDLE seems most appropriate */ - } - - pModule = NE_GetPtr(hModule); - if(!pModule) - { - ERR("Serious trouble. Just loaded module '%s' (hinst=0x%04x), but can't get NE_MODULE pointer\n", - libname, hinst); - return 6; /* ERROR_INVALID_HANDLE seems most appropriate */ - } - - TRACE("Loaded module '%s' at 0x%04x.\n", libname, hinst); - - /* - * Call initialization routines for all loaded DLLs. Note that - * when we load implicitly linked DLLs this will be done by InitTask(). - */ - if(pModule->flags & NE_FFLAGS_LIBMODULE) - { - NE_InitializeDLLs(hModule); - NE_DllProcessAttach(hModule); - } - } - return hinst; - } - - if(hinst != 2) - { - /* We quit searching when we get another error than 'File not found' */ - break; - } - } - return hinst; /* The last error that occurred */ -} - - -/********************************************************************** - * NE_CreateThread - * - * Create the thread for a 16-bit module. - */ -static HINSTANCE16 NE_CreateThread( NE_MODULE *pModule, WORD cmdShow, LPCSTR cmdline ) -{ - HANDLE hThread; - TDB *pTask; - HTASK16 hTask; - HINSTANCE16 instance = 0; - - if (!(hTask = TASK_SpawnTask( pModule, cmdShow, cmdline + 1, *cmdline, &hThread ))) - return 0; - - /* Post event to start the task */ - PostEvent16( hTask ); - - /* Wait until we get the instance handle */ - do - { - DirectedYield16( hTask ); - if (!IsTask16( hTask )) /* thread has died */ - { - DWORD exit_code; - WaitForSingleObject( hThread, INFINITE ); - GetExitCodeThread( hThread, &exit_code ); - CloseHandle( hThread ); - return exit_code; - } - if (!(pTask = TASK_GetPtr( hTask ))) break; - instance = pTask->hInstance; - GlobalUnlock16( hTask ); - } while (!instance); - - CloseHandle( hThread ); - return instance; -} - - -/********************************************************************** - * LoadModule (KERNEL.45) - */ -HINSTANCE16 WINAPI LoadModule16( LPCSTR name, LPVOID paramBlock ) -{ - BOOL lib_only = !paramBlock || (paramBlock == (LPVOID)-1); - LOADPARAMS16 *params; - HMODULE16 hModule; - NE_MODULE *pModule; - LPSTR cmdline; - WORD cmdShow; - - /* Load module */ - - if ( (hModule = NE_GetModuleByFilename(name) ) != 0 ) - { - /* Special case: second instance of an already loaded NE module */ - - if ( !( pModule = NE_GetPtr( hModule ) ) ) return (HINSTANCE16)11; - if ( pModule->module32 ) return (HINSTANCE16)21; - - /* Increment refcount */ - - pModule->count++; - } - else - { - /* Main case: load first instance of NE module */ - - if ( (hModule = MODULE_LoadModule16( name, FALSE, lib_only )) < 32 ) - return hModule; - - if ( !(pModule = NE_GetPtr( hModule )) ) - return (HINSTANCE16)11; - } - - /* If library module, we just retrieve the instance handle */ - - if ( ( pModule->flags & NE_FFLAGS_LIBMODULE ) || lib_only ) - return NE_GetInstance( pModule ); - - /* - * At this point, we need to create a new process. - * - * pModule points either to an already loaded module, whose refcount - * has already been incremented (to avoid having the module vanish - * in the meantime), or else to a stub module which contains only header - * information. - */ - params = (LOADPARAMS16 *)paramBlock; - cmdShow = ((WORD *)MapSL(params->showCmd))[1]; - cmdline = MapSL( params->cmdLine ); - return NE_CreateThread( pModule, cmdShow, cmdline ); -} - - -/********************************************************************** - * NE_StartTask - * - * Startup code for a new 16-bit task. - */ -DWORD NE_StartTask(void) -{ - TDB *pTask = TASK_GetCurrent(); - NE_MODULE *pModule = NE_GetPtr( pTask->hModule ); - HINSTANCE16 hInstance, hPrevInstance; - SEGTABLEENTRY *pSegTable = NE_SEG_TABLE( pModule ); - WORD sp; - - if ( pModule->count > 0 ) - { - /* Second instance of an already loaded NE module */ - /* Note that the refcount was already incremented by the parent */ - - hPrevInstance = NE_GetInstance( pModule ); - - if ( pModule->dgroup ) - if ( NE_CreateSegment( pModule, pModule->dgroup ) ) - NE_LoadSegment( pModule, pModule->dgroup ); - - hInstance = NE_GetInstance( pModule ); - TRACE("created second instance %04x[%d] of instance %04x.\n", hInstance, pModule->dgroup, hPrevInstance); - - } - else - { - /* Load first instance of NE module */ - - pModule->flags |= NE_FFLAGS_GUI; /* FIXME: is this necessary? */ - - hInstance = NE_DoLoadModule( pModule ); - hPrevInstance = 0; - } - - if ( hInstance >= 32 ) - { - CONTEXT86 context; - - /* Enter instance handles into task struct */ - - pTask->hInstance = hInstance; - pTask->hPrevInstance = hPrevInstance; - - /* Use DGROUP for 16-bit stack */ - - if (!(sp = pModule->sp)) - sp = pSegTable[pModule->ss-1].minsize + pModule->stack_size; - sp &= ~1; - sp -= sizeof(STACK16FRAME); - pTask->teb->cur_stack = MAKESEGPTR( GlobalHandleToSel16(hInstance), sp ); - - /* Registers at initialization must be: - * ax zero - * bx stack size in bytes - * cx heap size in bytes - * si previous app instance - * di current app instance - * bp zero - * es selector to the PSP - * ds dgroup of the application - * ss stack selector - * sp top of the stack - */ - memset( &context, 0, sizeof(context) ); - context.SegCs = GlobalHandleToSel16(pSegTable[pModule->cs - 1].hSeg); - context.SegDs = GlobalHandleToSel16(pTask->hInstance); - context.SegEs = pTask->hPDB; - context.Eip = pModule->ip; - context.Ebx = pModule->stack_size; - context.Ecx = pModule->heap_size; - context.Edi = pTask->hInstance; - context.Esi = pTask->hPrevInstance; - - /* Now call 16-bit entry point */ - - TRACE("Starting main program: cs:ip=%04lx:%04lx ds=%04lx ss:sp=%04x:%04x\n", - context.SegCs, context.Eip, context.SegDs, - SELECTOROF(pTask->teb->cur_stack), - OFFSETOF(pTask->teb->cur_stack) ); - - wine_call_to_16_regs_short( &context, 0 ); - ExitThread( LOWORD(context.Eax) ); - } - return hInstance; /* error code */ -} - -/*********************************************************************** - * LoadLibrary (KERNEL.95) - * LoadLibrary16 (KERNEL32.35) - */ -HINSTANCE16 WINAPI LoadLibrary16( LPCSTR libname ) -{ - return LoadModule16(libname, (LPVOID)-1 ); -} - - -/********************************************************************** - * MODULE_CallWEP - * - * Call a DLL's WEP, allowing it to shut down. - * FIXME: we always pass the WEP WEP_FREE_DLL, never WEP_SYSTEM_EXIT - */ -static BOOL16 MODULE_CallWEP( HMODULE16 hModule ) -{ - BOOL16 ret; - FARPROC16 WEP = GetProcAddress16( hModule, "WEP" ); - if (!WEP) return FALSE; - - __TRY - { - ret = NE_CallTo16_word_w( WEP, WEP_FREE_DLL ); - } - __EXCEPT(page_fault) - { - WARN("Page fault\n"); - ret = 0; - } - __ENDTRY - - return ret; -} - - -/********************************************************************** - * NE_FreeModule - * - * Implementation of FreeModule16(). - */ -static BOOL16 NE_FreeModule( HMODULE16 hModule, BOOL call_wep ) -{ - HMODULE16 *hPrevModule; - NE_MODULE *pModule; - HMODULE16 *pModRef; - int i; - - if (!(pModule = NE_GetPtr( hModule ))) return FALSE; - hModule = pModule->self; - - TRACE("%04x count %d\n", hModule, pModule->count ); - - if (((INT16)(--pModule->count)) > 0 ) return TRUE; - else pModule->count = 0; - - if (pModule->flags & NE_FFLAGS_BUILTIN) - return FALSE; /* Can't free built-in module */ - - if (call_wep && !(pModule->flags & NE_FFLAGS_WIN32)) - { - /* Free the objects owned by the DLL module */ - NE_CallUserSignalProc( hModule, USIG16_DLL_UNLOAD ); - - if (pModule->flags & NE_FFLAGS_LIBMODULE) - MODULE_CallWEP( hModule ); - else - call_wep = FALSE; /* We are freeing a task -> no more WEPs */ - } - - - /* Clear magic number just in case */ - - pModule->magic = pModule->self = 0; - - /* Remove it from the linked list */ - - hPrevModule = &hFirstModule; - while (*hPrevModule && (*hPrevModule != hModule)) - { - hPrevModule = &(NE_GetPtr( *hPrevModule ))->next; - } - if (*hPrevModule) *hPrevModule = pModule->next; - - /* Free the referenced modules */ - - pModRef = (HMODULE16*)NE_MODULE_TABLE( pModule ); - for (i = 0; i < pModule->modref_count; i++, pModRef++) - { - NE_FreeModule( *pModRef, call_wep ); - } - - /* Free the module storage */ - - GlobalFreeAll16( hModule ); - - /* Remove module from cache */ - - if (pCachedModule == pModule) pCachedModule = NULL; - return TRUE; -} - - -/********************************************************************** - * FreeModule (KERNEL.46) - */ -BOOL16 WINAPI FreeModule16( HMODULE16 hModule ) -{ - return NE_FreeModule( hModule, TRUE ); -} - - -/*********************************************************************** - * FreeLibrary (KERNEL.96) - * FreeLibrary16 (KERNEL32.36) - */ -void WINAPI FreeLibrary16( HINSTANCE16 handle ) -{ - TRACE("%04x\n", handle ); - FreeModule16( handle ); -} - - -/********************************************************************** - * GetModuleName (KERNEL.27) - */ -BOOL16 WINAPI GetModuleName16( HINSTANCE16 hinst, LPSTR buf, INT16 count ) -{ - NE_MODULE *pModule; - BYTE *p; - - if (!(pModule = NE_GetPtr( hinst ))) return FALSE; - p = (BYTE *)pModule + pModule->name_table; - if (count > *p) count = *p + 1; - if (count > 0) - { - memcpy( buf, p + 1, count - 1 ); - buf[count-1] = '\0'; - } - return TRUE; -} - - -/********************************************************************** - * GetModuleUsage (KERNEL.48) - */ -INT16 WINAPI GetModuleUsage16( HINSTANCE16 hModule ) -{ - NE_MODULE *pModule = NE_GetPtr( hModule ); - return pModule ? pModule->count : 0; -} - - -/********************************************************************** - * GetExpWinVer (KERNEL.167) - */ -WORD WINAPI GetExpWinVer16( HMODULE16 hModule ) -{ - NE_MODULE *pModule = NE_GetPtr( hModule ); - if ( !pModule ) return 0; - - /* - * For built-in modules, fake the expected version the module should - * have according to the Windows version emulated by Wine - */ - if ( !pModule->expected_version ) - { - OSVERSIONINFOA versionInfo; - versionInfo.dwOSVersionInfoSize = sizeof(versionInfo); - - if ( GetVersionExA( &versionInfo ) ) - pModule->expected_version = - (versionInfo.dwMajorVersion & 0xff) << 8 - | (versionInfo.dwMinorVersion & 0xff); - } - - return pModule->expected_version; -} - - /********************************************************************** * GetModuleFileName (KERNEL.49) * @@ -1437,120 +244,6 @@ INT16 WINAPI GetModuleFileName16( HINSTANCE16 hModule, LPSTR lpFileName, } -/*********************************************************************** - * WinExec (KERNEL.166) - */ -HINSTANCE16 WINAPI WinExec16( LPCSTR lpCmdLine, UINT16 nCmdShow ) -{ - LPCSTR p, args = NULL; - LPCSTR name_beg, name_end; - LPSTR name, cmdline; - int arglen; - HINSTANCE16 ret; - char buffer[MAX_PATH]; - - if (*lpCmdLine == '"') /* has to be only one and only at beginning ! */ - { - name_beg = lpCmdLine+1; - p = strchr ( lpCmdLine+1, '"' ); - if (p) - { - name_end = p; - args = strchr ( p, ' ' ); - } - else /* yes, even valid with trailing '"' missing */ - name_end = lpCmdLine+strlen(lpCmdLine); - } - else - { - name_beg = lpCmdLine; - args = strchr( lpCmdLine, ' ' ); - name_end = args ? args : lpCmdLine+strlen(lpCmdLine); - } - - if ((name_beg == lpCmdLine) && (!args)) - { /* just use the original cmdline string as file name */ - name = (LPSTR)lpCmdLine; - } - else - { - if (!(name = HeapAlloc( GetProcessHeap(), 0, name_end - name_beg + 1 ))) - return ERROR_NOT_ENOUGH_MEMORY; - memcpy( name, name_beg, name_end - name_beg ); - name[name_end - name_beg] = '\0'; - } - - if (args) - { - args++; - arglen = strlen(args); - cmdline = HeapAlloc( GetProcessHeap(), 0, 2 + arglen ); - cmdline[0] = (BYTE)arglen; - strcpy( cmdline + 1, args ); - } - else - { - cmdline = HeapAlloc( GetProcessHeap(), 0, 2 ); - cmdline[0] = cmdline[1] = 0; - } - - TRACE("name: '%s', cmdline: '%.*s'\n", name, cmdline[0], &cmdline[1]); - - if (SearchPathA( NULL, name, ".exe", sizeof(buffer), buffer, NULL )) - { - LOADPARAMS16 params; - WORD showCmd[2]; - showCmd[0] = 2; - showCmd[1] = nCmdShow; - - params.hEnvironment = 0; - params.cmdLine = MapLS( cmdline ); - params.showCmd = MapLS( showCmd ); - params.reserved = 0; - - ret = LoadModule16( buffer, ¶ms ); - UnMapLS( params.cmdLine ); - UnMapLS( params.showCmd ); - } - else ret = GetLastError(); - - HeapFree( GetProcessHeap(), 0, cmdline ); - if (name != lpCmdLine) HeapFree( GetProcessHeap(), 0, name ); - - if (ret == 21) /* 32-bit module */ - { - DWORD count; - ReleaseThunkLock( &count ); - ret = LOWORD( WinExec( lpCmdLine, nCmdShow ) ); - RestoreThunkLock( count ); - } - return ret; -} - -/********************************************************************** - * GetModuleHandle (KERNEL.47) - * - * Find a module from a module name. - * - * NOTE: The current implementation works the same way the Windows 95 one - * does. Do not try to 'fix' it, fix the callers. - * + It does not do ANY extension handling (except that strange .EXE bit)! - * + It does not care about paths, just about basenames. (same as Windows) - * - * RETURNS - * LOWORD: - * the win16 module handle if found - * 0 if not - * HIWORD (undocumented, see "Undocumented Windows", chapter 5): - * Always hFirstModule - */ -DWORD WINAPI WIN16_GetModuleHandle( SEGPTR name ) -{ - if (HIWORD(name) == 0) - return MAKELONG(GetExePtr( (HINSTANCE16)name), hFirstModule ); - return MAKELONG(GetModuleHandle16( MapSL(name)), hFirstModule ); -} - /*********************************************************************** * GetModuleHandle16 (KERNEL32.@) */ @@ -1647,117 +340,9 @@ HMODULE16 WINAPI GetModuleHandle16( LPCSTR name ) if (!FILE_strcasecmp(loadedfn, s)) return hModule; } - - /* If the extension of 'name' is '.EXE' and the base filename of 'name' - * matches the base filename of the module filename of some 32-bit module: - * Return the corresponding 16-bit dummy module handle. - */ - if (len >= 4 && !FILE_strcasecmp(name+len-4, ".EXE")) - { - HMODULE hModule = GetModuleHandleA( name ); - if ( hModule ) - return MapHModuleLS( hModule ); - } - - if (!strcmp(tmpstr,"MSDOS")) - return 1; - - if (!strcmp(tmpstr,"TIMER")) - { - FIXME("Eh... Should return caller's code segment, expect crash\n"); - return 0; - } - return 0; } -/********************************************************************** - * NE_GetModuleByFilename - */ -static HMODULE16 NE_GetModuleByFilename( LPCSTR name ) -{ - HMODULE16 hModule; - LPSTR s, p; - BYTE len, *name_table; - char tmpstr[MAX_PATH]; - NE_MODULE *pModule; - - lstrcpynA(tmpstr, name, sizeof(tmpstr)); - - /* If the base filename of 'name' matches the base filename of the module - * filename of some module (case-insensitive compare): - * Return its handle. - */ - - /* basename: search backwards in passed name to \ / or : */ - s = tmpstr + strlen(tmpstr); - while (s > tmpstr) - { - if (s[-1]=='/' || s[-1]=='\\' || s[-1]==':') - break; - s--; - } - - /* search this in loaded filename list */ - for (hModule = hFirstModule; hModule ; hModule = pModule->next) - { - char *loadedfn; - OFSTRUCT *ofs; - - pModule = NE_GetPtr( hModule ); - if (!pModule) break; - if (!pModule->fileinfo) continue; - if (pModule->flags & NE_FFLAGS_WIN32) continue; - - ofs = (OFSTRUCT*)((BYTE *)pModule + pModule->fileinfo); - loadedfn = ((char*)ofs->szPathName) + strlen(ofs->szPathName); - /* basename: search backwards in pathname to \ / or : */ - while (loadedfn > (char*)ofs->szPathName) - { - if (loadedfn[-1]=='/' || loadedfn[-1]=='\\' || loadedfn[-1]==':') - break; - loadedfn--; - } - /* case insensitive compare ... */ - if (!FILE_strcasecmp(loadedfn, s)) - return hModule; - } - /* If basename (without ext) matches the module name of a module: - * Return its handle. - */ - - if ( (p = strrchr( s, '.' )) != NULL ) *p = '\0'; - len = strlen(s); - - for (hModule = hFirstModule; hModule ; hModule = pModule->next) - { - pModule = NE_GetPtr( hModule ); - if (!pModule) break; - if (pModule->flags & NE_FFLAGS_WIN32) continue; - - name_table = (BYTE *)pModule + pModule->name_table; - if ((*name_table == len) && !FILE_strncasecmp(s, name_table+1, len)) - return hModule; - } - - return 0; -} - -/*********************************************************************** - * GetProcAddress16 (KERNEL32.37) - * Get procaddress in 16bit module from win32... (kernel32 undoc. ordinal func) - */ -FARPROC16 WINAPI WIN32_GetProcAddress16( HMODULE hModule, LPCSTR name ) -{ - if (!hModule) return 0; - if (HIWORD(hModule)) - { - WARN("hModule is Win32 handle (%p)\n", hModule ); - return 0; - } - return GetProcAddress16( LOWORD(hModule), name ); -} - /*********************************************************************** * GetProcAddress (KERNEL.50) */ @@ -1816,254 +401,3 @@ SEGPTR WINAPI HasGPHandler16( SEGPTR address ) return 0; } - - -/********************************************************************** - * ModuleFirst (TOOLHELP.59) - */ -BOOL16 WINAPI ModuleFirst16( MODULEENTRY *lpme ) -{ - lpme->wNext = hFirstModule; - return ModuleNext16( lpme ); -} - - -/********************************************************************** - * ModuleNext (TOOLHELP.60) - */ -BOOL16 WINAPI ModuleNext16( MODULEENTRY *lpme ) -{ - NE_MODULE *pModule; - char *name; - - if (!lpme->wNext) return FALSE; - if (!(pModule = NE_GetPtr( lpme->wNext ))) return FALSE; - name = (char *)pModule + pModule->name_table; - memcpy( lpme->szModule, name + 1, min(*name, MAX_MODULE_NAME) ); - lpme->szModule[min(*name, MAX_MODULE_NAME)] = '\0'; - lpme->hModule = lpme->wNext; - lpme->wcUsage = pModule->count; - lstrcpynA( lpme->szExePath, NE_MODULE_NAME(pModule), sizeof(lpme->szExePath) ); - lpme->wNext = pModule->next; - return TRUE; -} - - -/********************************************************************** - * ModuleFindName (TOOLHELP.61) - */ -BOOL16 WINAPI ModuleFindName16( MODULEENTRY *lpme, LPCSTR name ) -{ - lpme->wNext = GetModuleHandle16( name ); - return ModuleNext16( lpme ); -} - - -/********************************************************************** - * ModuleFindHandle (TOOLHELP.62) - */ -BOOL16 WINAPI ModuleFindHandle16( MODULEENTRY *lpme, HMODULE16 hModule ) -{ - hModule = GetExePtr( hModule ); - lpme->wNext = hModule; - return ModuleNext16( lpme ); -} - - -/*************************************************************************** - * IsRomModule (KERNEL.323) - */ -BOOL16 WINAPI IsRomModule16( HMODULE16 unused ) -{ - return FALSE; -} - -/*************************************************************************** - * IsRomFile (KERNEL.326) - */ -BOOL16 WINAPI IsRomFile16( HFILE16 unused ) -{ - return FALSE; -} - -/*********************************************************************** - * create_dummy_module - * - * Create a dummy NE module for Win32 or Winelib. - */ -static HMODULE16 create_dummy_module( HMODULE module32 ) -{ - HMODULE16 hModule; - NE_MODULE *pModule; - SEGTABLEENTRY *pSegment; - char *pStr,*s; - unsigned int len; - const char* basename; - OFSTRUCT *ofs; - int of_size, size; - char filename[MAX_PATH]; - IMAGE_NT_HEADERS *nt = RtlImageNtHeader( module32 ); - - if (!nt) return (HMODULE16)11; /* invalid exe */ - - /* Extract base filename */ - GetModuleFileNameA( module32, filename, sizeof(filename) ); - basename = strrchr(filename, '\\'); - if (!basename) basename = filename; - else basename++; - len = strlen(basename); - if ((s = strchr(basename, '.'))) len = s - basename; - - /* Allocate module */ - of_size = sizeof(OFSTRUCT) - sizeof(ofs->szPathName) - + strlen(filename) + 1; - size = sizeof(NE_MODULE) + - /* loaded file info */ - ((of_size + 3) & ~3) + - /* segment table: DS,CS */ - 2 * sizeof(SEGTABLEENTRY) + - /* name table */ - len + 2 + - /* several empty tables */ - 8; - - hModule = GlobalAlloc16( GMEM_MOVEABLE | GMEM_ZEROINIT, size ); - if (!hModule) return (HMODULE16)11; /* invalid exe */ - - FarSetOwner16( hModule, hModule ); - pModule = (NE_MODULE *)GlobalLock16( hModule ); - - /* Set all used entries */ - pModule->magic = IMAGE_OS2_SIGNATURE; - pModule->count = 1; - pModule->next = 0; - pModule->flags = NE_FFLAGS_WIN32; - pModule->dgroup = 0; - pModule->ss = 1; - pModule->cs = 2; - pModule->heap_size = 0; - pModule->stack_size = 0; - pModule->seg_count = 2; - pModule->modref_count = 0; - pModule->nrname_size = 0; - pModule->fileinfo = sizeof(NE_MODULE); - pModule->os_flags = NE_OSFLAGS_WINDOWS; - pModule->self = hModule; - pModule->module32 = module32; - - /* Set version and flags */ - pModule->expected_version = ((nt->OptionalHeader.MajorSubsystemVersion & 0xff) << 8 ) | - (nt->OptionalHeader.MinorSubsystemVersion & 0xff); - if (nt->FileHeader.Characteristics & IMAGE_FILE_DLL) - pModule->flags |= NE_FFLAGS_LIBMODULE | NE_FFLAGS_SINGLEDATA; - - /* Set loaded file information */ - ofs = (OFSTRUCT *)(pModule + 1); - memset( ofs, 0, of_size ); - ofs->cBytes = of_size < 256 ? of_size : 255; /* FIXME */ - strcpy( ofs->szPathName, filename ); - - pSegment = (SEGTABLEENTRY*)((char*)(pModule + 1) + ((of_size + 3) & ~3)); - pModule->seg_table = (int)pSegment - (int)pModule; - /* Data segment */ - pSegment->size = 0; - pSegment->flags = NE_SEGFLAGS_DATA; - pSegment->minsize = 0x1000; - pSegment++; - /* Code segment */ - pSegment->flags = 0; - pSegment++; - - /* Module name */ - pStr = (char *)pSegment; - pModule->name_table = (int)pStr - (int)pModule; - assert(len<256); - *pStr = len; - lstrcpynA( pStr+1, basename, len+1 ); - pStr += len+2; - - /* All tables zero terminated */ - pModule->res_table = pModule->import_table = pModule->entry_table = (int)pStr - (int)pModule; - - NE_RegisterModule( pModule ); - LoadLibraryA( filename ); /* increment the ref count of the 32-bit module */ - return hModule; -} - -/*************************************************************************** - * MapHModuleLS (KERNEL32.@) - */ -HMODULE16 WINAPI MapHModuleLS(HMODULE hmod) -{ - HMODULE16 ret; - NE_MODULE *pModule; - - if (!hmod) - return TASK_GetCurrent()->hInstance; - if (!HIWORD(hmod)) - return LOWORD(hmod); /* we already have a 16 bit module handle */ - pModule = (NE_MODULE*)GlobalLock16(hFirstModule); - while (pModule) { - if (pModule->module32 == hmod) - return pModule->self; - pModule = (NE_MODULE*)GlobalLock16(pModule->next); - } - if ((ret = create_dummy_module( hmod )) < 32) - { - SetLastError(ret); - ret = 0; - } - return ret; -} - -/*************************************************************************** - * MapHModuleSL (KERNEL32.@) - */ -HMODULE WINAPI MapHModuleSL(HMODULE16 hmod) { - NE_MODULE *pModule; - - if (!hmod) { - TDB *pTask = TASK_GetCurrent(); - hmod = pTask->hModule; - } - pModule = (NE_MODULE*)GlobalLock16(hmod); - if ( (pModule->magic!=IMAGE_OS2_SIGNATURE) || - !(pModule->flags & NE_FFLAGS_WIN32) - ) - return 0; - return pModule->module32; -} - -/*************************************************************************** - * MapHInstLS (KERNEL32.@) - * MapHInstLS (KERNEL.472) - */ -void WINAPI MapHInstLS( CONTEXT86 *context ) -{ - context->Eax = MapHModuleLS( (HMODULE)context->Eax ); -} - -/*************************************************************************** - * MapHInstSL (KERNEL32.@) - * MapHInstSL (KERNEL.473) - */ -void WINAPI MapHInstSL( CONTEXT86 *context ) -{ - context->Eax = (DWORD)MapHModuleSL( context->Eax ); -} - -/*************************************************************************** - * MapHInstLS_PN (KERNEL32.@) - */ -void WINAPI MapHInstLS_PN( CONTEXT86 *context ) -{ - if (context->Eax) context->Eax = MapHModuleLS( (HMODULE)context->Eax ); -} - -/*************************************************************************** - * MapHInstSL_PN (KERNEL32.@) - */ -void WINAPI MapHInstSL_PN( CONTEXT86 *context ) -{ - if (context->Eax) context->Eax = (DWORD)MapHModuleSL( context->Eax ); -} diff --git a/loader/task.c b/loader/task.c index f83600874f6..e954081b9ff 100644 --- a/loader/task.c +++ b/loader/task.c @@ -42,7 +42,6 @@ #include "winternl.h" #include "selectors.h" #include "wine/server.h" -#include "syslevel.h" #include "stackframe.h" #include "task.h" #include "thread.h" @@ -51,8 +50,6 @@ #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(task); -WINE_DECLARE_DEBUG_CHANNEL(relay); -WINE_DECLARE_DEBUG_CHANNEL(toolhelp); /* Min. number of thunks allocated when creating a new segment */ #define MIN_THUNKS 32 @@ -61,42 +58,12 @@ WINE_DECLARE_DEBUG_CHANNEL(toolhelp); static THHOOK DefaultThhook; THHOOK *pThhook = &DefaultThhook; -#define hCurrentTask (pThhook->CurTDB) #define hFirstTask (pThhook->HeadTDB) -#define hLockedTask (pThhook->LockTDB) - -static UINT16 nTaskCount = 0; - -static HTASK16 initial_task; - -/*********************************************************************** - * TASK_InstallTHHook - */ -void TASK_InstallTHHook( THHOOK *pNewThhook ) -{ - THHOOK *pOldThhook = pThhook; - - pThhook = pNewThhook? pNewThhook : &DefaultThhook; - - *pThhook = *pOldThhook; -} - -/*********************************************************************** - * TASK_GetNextTask - */ -HTASK16 TASK_GetNextTask( HTASK16 hTask ) -{ - TDB* pTask = TASK_GetPtr( hTask ); - - if (pTask->hNext) return pTask->hNext; - return (hFirstTask != hTask) ? hFirstTask : 0; -} - /*********************************************************************** * TASK_GetPtr */ -TDB *TASK_GetPtr( HTASK16 hTask ) +static TDB *TASK_GetPtr( HTASK16 hTask ) { return GlobalLock16( hTask ); } @@ -111,532 +78,6 @@ TDB *TASK_GetCurrent(void) } -/*********************************************************************** - * TASK_LinkTask - */ -static void TASK_LinkTask( HTASK16 hTask ) -{ - HTASK16 *prevTask; - TDB *pTask; - - if (!(pTask = TASK_GetPtr( hTask ))) return; - prevTask = &hFirstTask; - while (*prevTask) - { - TDB *prevTaskPtr = TASK_GetPtr( *prevTask ); - if (prevTaskPtr->priority >= pTask->priority) break; - prevTask = &prevTaskPtr->hNext; - } - pTask->hNext = *prevTask; - *prevTask = hTask; - nTaskCount++; -} - - -/*********************************************************************** - * TASK_UnlinkTask - */ -static void TASK_UnlinkTask( HTASK16 hTask ) -{ - HTASK16 *prevTask; - TDB *pTask; - - prevTask = &hFirstTask; - while (*prevTask && (*prevTask != hTask)) - { - pTask = TASK_GetPtr( *prevTask ); - prevTask = &pTask->hNext; - } - if (*prevTask) - { - pTask = TASK_GetPtr( *prevTask ); - *prevTask = pTask->hNext; - pTask->hNext = 0; - nTaskCount--; - } -} - - -/*********************************************************************** - * TASK_CreateThunks - * - * Create a thunk free-list in segment 'handle', starting from offset 'offset' - * and containing 'count' entries. - */ -static void TASK_CreateThunks( HGLOBAL16 handle, WORD offset, WORD count ) -{ - int i; - WORD free; - THUNKS *pThunk; - - pThunk = (THUNKS *)((BYTE *)GlobalLock16( handle ) + offset); - pThunk->next = 0; - pThunk->magic = THUNK_MAGIC; - pThunk->free = (int)&pThunk->thunks - (int)pThunk; - free = pThunk->free; - for (i = 0; i < count-1; i++) - { - free += 8; /* Offset of next thunk */ - pThunk->thunks[4*i] = free; - } - pThunk->thunks[4*i] = 0; /* Last thunk */ -} - - -/*********************************************************************** - * TASK_AllocThunk - * - * Allocate a thunk for MakeProcInstance(). - */ -static SEGPTR TASK_AllocThunk(void) -{ - TDB *pTask; - THUNKS *pThunk; - WORD sel, base; - - if (!(pTask = TASK_GetCurrent())) return 0; - sel = pTask->hCSAlias; - pThunk = &pTask->thunks; - base = (int)pThunk - (int)pTask; - while (!pThunk->free) - { - sel = pThunk->next; - if (!sel) /* Allocate a new segment */ - { - sel = GLOBAL_Alloc( GMEM_FIXED, sizeof(THUNKS) + (MIN_THUNKS-1)*8, - pTask->hPDB, WINE_LDT_FLAGS_CODE ); - if (!sel) return (SEGPTR)0; - TASK_CreateThunks( sel, 0, MIN_THUNKS ); - pThunk->next = sel; - } - pThunk = (THUNKS *)GlobalLock16( sel ); - base = 0; - } - base += pThunk->free; - pThunk->free = *(WORD *)((BYTE *)pThunk + pThunk->free); - return MAKESEGPTR( sel, base ); -} - - -/*********************************************************************** - * TASK_FreeThunk - * - * Free a MakeProcInstance() thunk. - */ -static BOOL TASK_FreeThunk( SEGPTR thunk ) -{ - TDB *pTask; - THUNKS *pThunk; - WORD sel, base; - - if (!(pTask = TASK_GetCurrent())) return 0; - sel = pTask->hCSAlias; - pThunk = &pTask->thunks; - base = (int)pThunk - (int)pTask; - while (sel && (sel != HIWORD(thunk))) - { - sel = pThunk->next; - pThunk = (THUNKS *)GlobalLock16( sel ); - base = 0; - } - if (!sel) return FALSE; - *(WORD *)((BYTE *)pThunk + LOWORD(thunk) - base) = pThunk->free; - pThunk->free = LOWORD(thunk) - base; - return TRUE; -} - - -/*********************************************************************** - * TASK_Create - * - * NOTE: This routine might be called by a Win32 thread. Thus, we need - * to be careful to protect global data structures. We do this - * by entering the Win16Lock while linking the task into the - * global task list. - */ -static TDB *TASK_Create( NE_MODULE *pModule, UINT16 cmdShow, TEB *teb, LPCSTR cmdline, BYTE len ) -{ - HTASK16 hTask; - TDB *pTask; - FARPROC16 proc; - HMODULE16 hModule = pModule ? pModule->self : 0; - - /* Allocate the task structure */ - - hTask = GlobalAlloc16( GMEM_FIXED | GMEM_ZEROINIT, sizeof(TDB) ); - if (!hTask) return NULL; - pTask = TASK_GetPtr( hTask ); - FarSetOwner16( hTask, hModule ); - - /* Fill the task structure */ - - pTask->hSelf = hTask; - - if (teb && teb->tibflags & TEBF_WIN32) - { - pTask->flags |= TDBF_WIN32; - pTask->hInstance = hModule; - pTask->hPrevInstance = 0; - /* NOTE: for 16-bit tasks, the instance handles are updated later on - in NE_InitProcess */ - } - - pTask->version = pModule ? pModule->expected_version : 0x0400; - pTask->hModule = hModule; - pTask->hParent = GetCurrentTask(); - pTask->magic = TDB_MAGIC; - pTask->nCmdShow = cmdShow; - pTask->teb = teb; - pTask->curdrive = DRIVE_GetCurrentDrive() | 0x80; - strcpy( pTask->curdir, "\\" ); - WideCharToMultiByte(CP_ACP, 0, DRIVE_GetDosCwd(DRIVE_GetCurrentDrive()), -1, - pTask->curdir + 1, sizeof(pTask->curdir) - 1, NULL, NULL); - pTask->curdir[sizeof(pTask->curdir) - 1] = 0; /* ensure 0 termination */ - - /* Create the thunks block */ - - TASK_CreateThunks( hTask, (int)&pTask->thunks - (int)pTask, 7 ); - - /* Copy the module name */ - - if (hModule) - { - char name[10]; - GetModuleName16( hModule, name, sizeof(name) ); - strncpy( pTask->module_name, name, sizeof(pTask->module_name) ); - pTask->compat_flags = GetProfileIntA( "Compatibility", name, 0 ); - } - - /* Allocate a selector for the PDB */ - - pTask->hPDB = GLOBAL_CreateBlock( GMEM_FIXED, &pTask->pdb, sizeof(PDB16), - hModule, WINE_LDT_FLAGS_DATA ); - - /* Fill the PDB */ - - pTask->pdb.int20 = 0x20cd; - pTask->pdb.dispatcher[0] = 0x9a; /* ljmp */ - proc = GetProcAddress16( GetModuleHandle16("KERNEL"), "DOS3Call" ); - memcpy( &pTask->pdb.dispatcher[1], &proc, sizeof(proc) ); - pTask->pdb.savedint22 = 0; - pTask->pdb.savedint23 = 0; - pTask->pdb.savedint24 = 0; - pTask->pdb.fileHandlesPtr = - MAKESEGPTR( GlobalHandleToSel16(pTask->hPDB), (int)&((PDB16 *)0)->fileHandles ); - pTask->pdb.hFileHandles = 0; - memset( pTask->pdb.fileHandles, 0xff, sizeof(pTask->pdb.fileHandles) ); - /* FIXME: should we make a copy of the environment? */ - pTask->pdb.environment = SELECTOROF(GetDOSEnvironment16()); - pTask->pdb.nbFiles = 20; - - /* Fill the command line */ - - if (!cmdline) - { - cmdline = GetCommandLineA(); - /* remove the first word (program name) */ - if (*cmdline == '"') - if (!(cmdline = strchr( cmdline+1, '"' ))) cmdline = GetCommandLineA(); - while (*cmdline && (*cmdline != ' ') && (*cmdline != '\t')) cmdline++; - while ((*cmdline == ' ') || (*cmdline == '\t')) cmdline++; - len = strlen(cmdline); - } - if (len >= sizeof(pTask->pdb.cmdLine)) len = sizeof(pTask->pdb.cmdLine)-1; - pTask->pdb.cmdLine[0] = len; - memcpy( pTask->pdb.cmdLine + 1, cmdline, len ); - /* pTask->pdb.cmdLine[len+1] = 0; */ - - TRACE("cmdline='%.*s' task=%04x\n", len, cmdline, hTask ); - - /* Allocate a code segment alias for the TDB */ - - pTask->hCSAlias = GLOBAL_CreateBlock( GMEM_FIXED, (void *)pTask, - sizeof(TDB), pTask->hPDB, WINE_LDT_FLAGS_CODE ); - - /* Default DTA overwrites command line */ - - pTask->dta = MAKESEGPTR( pTask->hPDB, (int)&pTask->pdb.cmdLine - (int)&pTask->pdb ); - - /* Create scheduler event for 16-bit tasks */ - - if ( !(pTask->flags & TDBF_WIN32) ) - NtCreateEvent( &pTask->hEvent, EVENT_ALL_ACCESS, NULL, TRUE, FALSE ); - - /* Enter task handle into thread */ - - if (teb) teb->htask16 = hTask; - if (!initial_task) initial_task = hTask; - - return pTask; -} - - -/*********************************************************************** - * TASK_DeleteTask - */ -static void TASK_DeleteTask( HTASK16 hTask ) -{ - TDB *pTask; - HGLOBAL16 hPDB; - - if (!(pTask = TASK_GetPtr( hTask ))) return; - hPDB = pTask->hPDB; - - pTask->magic = 0xdead; /* invalidate signature */ - - /* Free the selector aliases */ - - GLOBAL_FreeBlock( pTask->hCSAlias ); - GLOBAL_FreeBlock( pTask->hPDB ); - - /* Free the task module */ - - FreeModule16( pTask->hModule ); - - /* Free the task structure itself */ - - GlobalFree16( hTask ); - - /* Free all memory used by this task (including the 32-bit stack, */ - /* the environment block and the thunk segments). */ - - GlobalFreeAll16( hPDB ); -} - - -/*********************************************************************** - * TASK_CreateMainTask - * - * Create a task for the main (32-bit) process. - */ -void TASK_CreateMainTask(void) -{ - TDB *pTask; - STARTUPINFOA startup_info; - UINT cmdShow = 1; /* SW_SHOWNORMAL but we don't want to include winuser.h here */ - - GetStartupInfoA( &startup_info ); - if (startup_info.dwFlags & STARTF_USESHOWWINDOW) cmdShow = startup_info.wShowWindow; - pTask = TASK_Create( NULL, cmdShow, NtCurrentTeb(), NULL, 0 ); - if (!pTask) - { - ERR("could not create task for main process\n"); - ExitProcess(1); - } - - /* Add the task to the linked list */ - /* (no need to get the win16 lock, we are the only thread at this point) */ - TASK_LinkTask( pTask->hSelf ); -} - - -/* startup routine for a new 16-bit thread */ -static DWORD CALLBACK task_start( TDB *pTask ) -{ - DWORD ret; - - NtCurrentTeb()->tibflags &= ~TEBF_WIN32; - NtCurrentTeb()->htask16 = pTask->hSelf; - - _EnterWin16Lock(); - TASK_LinkTask( pTask->hSelf ); - pTask->teb = NtCurrentTeb(); - ret = NE_StartTask(); - _LeaveWin16Lock(); - return ret; -} - - -/*********************************************************************** - * TASK_SpawnTask - * - * Spawn a new 16-bit task. - */ -HTASK16 TASK_SpawnTask( NE_MODULE *pModule, WORD cmdShow, - LPCSTR cmdline, BYTE len, HANDLE *hThread ) -{ - TDB *pTask; - - if (!(pTask = TASK_Create( pModule, cmdShow, NULL, cmdline, len ))) return 0; - if (!(*hThread = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)task_start, pTask, 0, NULL ))) - { - TASK_DeleteTask( pTask->hSelf ); - return 0; - } - return pTask->hSelf; -} - - -/*********************************************************************** - * TASK_ExitTask - */ -void TASK_ExitTask(void) -{ - TDB *pTask; - DWORD lockCount; - - /* Enter the Win16Lock to protect global data structures */ - _EnterWin16Lock(); - - pTask = TASK_GetCurrent(); - if ( !pTask ) - { - _LeaveWin16Lock(); - return; - } - - TRACE("Killing task %04x\n", pTask->hSelf ); - - /* Perform USER cleanup */ - - TASK_CallTaskSignalProc( USIG16_TERMINATION, pTask->hSelf ); - - /* Remove the task from the list to be sure we never switch back to it */ - TASK_UnlinkTask( pTask->hSelf ); - - if (!nTaskCount || (nTaskCount == 1 && hFirstTask == initial_task)) - { - TRACE("this is the last task, exiting\n" ); - ExitKernel16(); - } - - if( nTaskCount ) - { - TDB* p = TASK_GetPtr( hFirstTask ); - while( p ) - { - if( p->hYieldTo == pTask->hSelf ) p->hYieldTo = 0; - p = TASK_GetPtr( p->hNext ); - } - } - - pTask->nEvents = 0; - - if ( hLockedTask == pTask->hSelf ) - hLockedTask = 0; - - TASK_DeleteTask( pTask->hSelf ); - - /* ... and completely release the Win16Lock, just in case. */ - ReleaseThunkLock( &lockCount ); -} - - -/*********************************************************************** - * ExitKernel (KERNEL.2) - * - * Clean-up everything and exit the Wine process. - */ -void WINAPI ExitKernel16(void) -{ - WriteOutProfiles16(); - TerminateProcess( GetCurrentProcess(), 0 ); -} - - -/*********************************************************************** - * InitTask (KERNEL.91) - * - * Called by the application startup code. - */ -void WINAPI InitTask16( CONTEXT86 *context ) -{ - TDB *pTask; - INSTANCEDATA *pinstance; - SEGPTR ptr; - - context->Eax = 0; - if (!(pTask = TASK_GetCurrent())) return; - - /* Note: we need to trust that BX/CX contain the stack/heap sizes, - as some apps, notably Visual Basic apps, *modify* the heap/stack - size of the instance data segment before calling InitTask() */ - - /* Initialize the INSTANCEDATA structure */ - pinstance = MapSL( MAKESEGPTR(CURRENT_DS, 0) ); - pinstance->stackmin = OFFSETOF( pTask->teb->cur_stack ) + sizeof( STACK16FRAME ); - pinstance->stackbottom = pinstance->stackmin; /* yup, that's right. Confused me too. */ - pinstance->stacktop = ( pinstance->stackmin > LOWORD(context->Ebx) ? - pinstance->stackmin - LOWORD(context->Ebx) : 0 ) + 150; - - /* Initialize the local heap */ - if (LOWORD(context->Ecx)) - LocalInit16( GlobalHandleToSel16(pTask->hInstance), 0, LOWORD(context->Ecx) ); - - /* Initialize implicitly loaded DLLs */ - NE_InitializeDLLs( pTask->hModule ); - NE_DllProcessAttach( pTask->hModule ); - - /* Registers on return are: - * ax 1 if OK, 0 on error - * cx stack limit in bytes - * dx cmdShow parameter - * si instance handle of the previous instance - * di instance handle of the new task - * es:bx pointer to command line inside PSP - * - * 0 (=%bp) is pushed on the stack - */ - ptr = stack16_push( sizeof(WORD) ); - *(WORD *)MapSL(ptr) = 0; - context->Esp -= 2; - - context->Eax = 1; - - if (!pTask->pdb.cmdLine[0]) context->Ebx = 0x80; - else - { - LPBYTE p = &pTask->pdb.cmdLine[1]; - while ((*p == ' ') || (*p == '\t')) p++; - context->Ebx = 0x80 + (p - pTask->pdb.cmdLine); - } - context->Ecx = pinstance->stacktop; - context->Edx = pTask->nCmdShow; - context->Esi = (DWORD)pTask->hPrevInstance; - context->Edi = (DWORD)pTask->hInstance; - context->SegEs = (WORD)pTask->hPDB; -} - - -/*********************************************************************** - * WaitEvent (KERNEL.30) - */ -BOOL16 WINAPI WaitEvent16( HTASK16 hTask ) -{ - TDB *pTask; - - if (!hTask) hTask = GetCurrentTask(); - pTask = TASK_GetPtr( hTask ); - - if (pTask->flags & TDBF_WIN32) - { - FIXME("called for Win32 thread (%04x)!\n", NtCurrentTeb()->teb_sel); - return TRUE; - } - - if (pTask->nEvents > 0) - { - pTask->nEvents--; - return FALSE; - } - - if (pTask->teb == NtCurrentTeb()) - { - DWORD lockCount; - - NtResetEvent( pTask->hEvent, NULL ); - ReleaseThunkLock( &lockCount ); - SYSLEVEL_CheckNotLevel( 1 ); - WaitForSingleObject( pTask->hEvent, INFINITE ); - RestoreThunkLock( lockCount ); - if (pTask->nEvents > 0) pTask->nEvents--; - } - else FIXME("for other task %04x cur=%04x\n",pTask->hSelf,GetCurrentTask()); - - return TRUE; -} - - /*********************************************************************** * PostEvent (KERNEL.31) */ @@ -659,47 +100,6 @@ void WINAPI PostEvent16( HTASK16 hTask ) } -/*********************************************************************** - * SetPriority (KERNEL.32) - */ -void WINAPI SetPriority16( HTASK16 hTask, INT16 delta ) -{ - TDB *pTask; - INT16 newpriority; - - if (!hTask) hTask = GetCurrentTask(); - if (!(pTask = TASK_GetPtr( hTask ))) return; - newpriority = pTask->priority + delta; - if (newpriority < -32) newpriority = -32; - else if (newpriority > 15) newpriority = 15; - - pTask->priority = newpriority + 1; - TASK_UnlinkTask( pTask->hSelf ); - TASK_LinkTask( pTask->hSelf ); - pTask->priority--; -} - - -/*********************************************************************** - * LockCurrentTask (KERNEL.33) - */ -HTASK16 WINAPI LockCurrentTask16( BOOL16 bLock ) -{ - if (bLock) hLockedTask = GetCurrentTask(); - else hLockedTask = 0; - return hLockedTask; -} - - -/*********************************************************************** - * IsTaskLocked (KERNEL.122) - */ -HTASK16 WINAPI IsTaskLocked16(void) -{ - return hLockedTask; -} - - /*********************************************************************** * OldYield (KERNEL.117) */ @@ -711,461 +111,14 @@ void WINAPI OldYield16(void) RestoreThunkLock(count); } -/*********************************************************************** - * WIN32_OldYield (KERNEL.447) - */ -void WINAPI WIN32_OldYield16(void) -{ - DWORD count; - - ReleaseThunkLock(&count); - RestoreThunkLock(count); -} - /*********************************************************************** * DirectedYield (KERNEL.150) */ void WINAPI DirectedYield16( HTASK16 hTask ) { - TDB *pCurTask = TASK_GetCurrent(); - - if (!pCurTask || (pCurTask->flags & TDBF_WIN32)) OldYield16(); - else - { - TRACE("%04x: DirectedYield(%04x)\n", pCurTask->hSelf, hTask ); - pCurTask->hYieldTo = hTask; - OldYield16(); - TRACE("%04x: back from DirectedYield(%04x)\n", pCurTask->hSelf, hTask ); - } -} - -/*********************************************************************** - * Yield (KERNEL.29) - */ -void WINAPI Yield16(void) -{ - TDB *pCurTask = TASK_GetCurrent(); - - if (pCurTask) pCurTask->hYieldTo = 0; - if (pCurTask && pCurTask->hQueue) - { - HMODULE mod = GetModuleHandleA( "user32.dll" ); - if (mod) - { - FARPROC proc = GetProcAddress( mod, "UserYield16" ); - if (proc) - { - proc(); - return; - } - } - } OldYield16(); } -/*********************************************************************** - * KERNEL_490 (KERNEL.490) - */ -HTASK16 WINAPI KERNEL_490( HTASK16 someTask ) -{ - if ( !someTask ) return 0; - - FIXME("(%04x): stub\n", someTask ); - return 0; -} - -/*********************************************************************** - * MakeProcInstance (KERNEL.51) - */ -FARPROC16 WINAPI MakeProcInstance16( FARPROC16 func, HANDLE16 hInstance ) -{ - BYTE *thunk,*lfunc; - SEGPTR thunkaddr; - WORD hInstanceSelector; - - hInstanceSelector = GlobalHandleToSel16(hInstance); - - TRACE("(%08lx, %04x);\n", (DWORD)func, hInstance); - - if (!HIWORD(func)) { - /* Win95 actually protects via SEH, but this is better for debugging */ - WARN("Ouch ! Called with invalid func 0x%08lx !\n", (DWORD)func); - return (FARPROC16)0; - } - - if ( (GlobalHandleToSel16(CURRENT_DS) != hInstanceSelector) - && (hInstance != 0) - && (hInstance != 0xffff) ) - { - /* calling MPI with a foreign DSEG is invalid ! */ - WARN("Problem with hInstance? Got %04x, using %04x instead\n", - hInstance,CURRENT_DS); - } - - /* Always use the DSEG that MPI was entered with. - * We used to set hInstance to GetTaskDS16(), but this should be wrong - * as CURRENT_DS provides the DSEG value we need. - * ("calling" DS, *not* "task" DS !) */ - hInstanceSelector = CURRENT_DS; - hInstance = GlobalHandle16(hInstanceSelector); - - /* no thunking for DLLs */ - if (NE_GetPtr(FarGetOwner16(hInstance))->flags & NE_FFLAGS_LIBMODULE) - return func; - - thunkaddr = TASK_AllocThunk(); - if (!thunkaddr) return (FARPROC16)0; - thunk = MapSL( thunkaddr ); - lfunc = MapSL( (SEGPTR)func ); - - TRACE("(%08lx,%04x): got thunk %08lx\n", - (DWORD)func, hInstance, (DWORD)thunkaddr ); - if (((lfunc[0]==0x8c) && (lfunc[1]==0xd8)) || /* movw %ds, %ax */ - ((lfunc[0]==0x1e) && (lfunc[1]==0x58)) /* pushw %ds, popw %ax */ - ) { - WARN("This was the (in)famous \"thunk useless\" warning. We thought we have to overwrite with nop;nop;, but this isn't true.\n"); - } - - *thunk++ = 0xb8; /* movw instance, %ax */ - *thunk++ = (BYTE)(hInstanceSelector & 0xff); - *thunk++ = (BYTE)(hInstanceSelector >> 8); - *thunk++ = 0xea; /* ljmp func */ - *(DWORD *)thunk = (DWORD)func; - return (FARPROC16)thunkaddr; - /* CX reg indicates if thunkaddr != NULL, implement if needed */ -} - - -/*********************************************************************** - * FreeProcInstance (KERNEL.52) - */ -void WINAPI FreeProcInstance16( FARPROC16 func ) -{ - TRACE("(%08lx)\n", (DWORD)func ); - TASK_FreeThunk( (SEGPTR)func ); -} - -/********************************************************************** - * TASK_GetCodeSegment - * - * Helper function for GetCodeHandle/GetCodeInfo: Retrieve the module - * and logical segment number of a given code segment. - * - * 'proc' either *is* already a pair of module handle and segment number, - * in which case there's nothing to do. Otherwise, it is a pointer to - * a function, and we need to retrieve the code segment. If the pointer - * happens to point to a thunk, we'll retrieve info about the code segment - * where the function pointed to by the thunk resides, not the thunk itself. - * - * FIXME: if 'proc' is a SNOOP16 return stub, we should retrieve info about - * the function the snoop code will return to ... - * - */ -static BOOL TASK_GetCodeSegment( FARPROC16 proc, NE_MODULE **ppModule, - SEGTABLEENTRY **ppSeg, int *pSegNr ) -{ - NE_MODULE *pModule = NULL; - SEGTABLEENTRY *pSeg = NULL; - int segNr=0; - - /* Try pair of module handle / segment number */ - pModule = (NE_MODULE *) GlobalLock16( HIWORD( proc ) ); - if ( pModule && pModule->magic == IMAGE_OS2_SIGNATURE ) - { - segNr = LOWORD( proc ); - if ( segNr && segNr <= pModule->seg_count ) - pSeg = NE_SEG_TABLE( pModule ) + segNr-1; - } - - /* Try thunk or function */ - else - { - BYTE *thunk = MapSL( (SEGPTR)proc ); - WORD selector; - - if ((thunk[0] == 0xb8) && (thunk[3] == 0xea)) - selector = thunk[6] + (thunk[7] << 8); - else - selector = HIWORD( proc ); - - pModule = NE_GetPtr( GlobalHandle16( selector ) ); - pSeg = pModule? NE_SEG_TABLE( pModule ) : NULL; - - if ( pModule ) - for ( segNr = 1; segNr <= pModule->seg_count; segNr++, pSeg++ ) - if ( GlobalHandleToSel16(pSeg->hSeg) == selector ) - break; - - if ( pModule && segNr > pModule->seg_count ) - pSeg = NULL; - } - - /* Abort if segment not found */ - - if ( !pModule || !pSeg ) - return FALSE; - - /* Return segment data */ - - if ( ppModule ) *ppModule = pModule; - if ( ppSeg ) *ppSeg = pSeg; - if ( pSegNr ) *pSegNr = segNr; - - return TRUE; -} - -/********************************************************************** - * GetCodeHandle (KERNEL.93) - */ -HANDLE16 WINAPI GetCodeHandle16( FARPROC16 proc ) -{ - SEGTABLEENTRY *pSeg; - - if ( !TASK_GetCodeSegment( proc, NULL, &pSeg, NULL ) ) - return (HANDLE16)0; - - return pSeg->hSeg; -} - -/********************************************************************** - * GetCodeInfo (KERNEL.104) - */ -BOOL16 WINAPI GetCodeInfo16( FARPROC16 proc, SEGINFO *segInfo ) -{ - NE_MODULE *pModule; - SEGTABLEENTRY *pSeg; - int segNr; - - if ( !TASK_GetCodeSegment( proc, &pModule, &pSeg, &segNr ) ) - return FALSE; - - /* Fill in segment information */ - - segInfo->offSegment = pSeg->filepos; - segInfo->cbSegment = pSeg->size; - segInfo->flags = pSeg->flags; - segInfo->cbAlloc = pSeg->minsize; - segInfo->h = pSeg->hSeg; - segInfo->alignShift = pModule->alignment; - - if ( segNr == pModule->dgroup ) - segInfo->cbAlloc += pModule->heap_size + pModule->stack_size; - - /* Return module handle in %es */ - - CURRENT_STACK16->es = GlobalHandleToSel16( pModule->self ); - - return TRUE; -} - - -/********************************************************************** - * DefineHandleTable (KERNEL.94) - */ -BOOL16 WINAPI DefineHandleTable16( WORD wOffset ) -{ - FIXME("(%04x): stub ?\n", wOffset); - return TRUE; -} - - -/*********************************************************************** - * SetTaskQueue (KERNEL.34) - */ -HQUEUE16 WINAPI SetTaskQueue16( HTASK16 hTask, HQUEUE16 hQueue ) -{ - HQUEUE16 hPrev; - TDB *pTask; - - if (!hTask) hTask = GetCurrentTask(); - if (!(pTask = TASK_GetPtr( hTask ))) return 0; - - hPrev = pTask->hQueue; - pTask->hQueue = hQueue; - - return hPrev; -} - - -/*********************************************************************** - * GetTaskQueue (KERNEL.35) - */ -HQUEUE16 WINAPI GetTaskQueue16( HTASK16 hTask ) -{ - TDB *pTask; - - if (!hTask) hTask = GetCurrentTask(); - if (!(pTask = TASK_GetPtr( hTask ))) return 0; - return pTask->hQueue; -} - -/*********************************************************************** - * SetThreadQueue (KERNEL.463) - */ -HQUEUE16 WINAPI SetThreadQueue16( DWORD thread, HQUEUE16 hQueue ) -{ - TEB *teb = thread? THREAD_IdToTEB( thread ) : NtCurrentTeb(); - HQUEUE16 oldQueue = teb? teb->queue : 0; - - if ( teb ) - { - teb->queue = hQueue; - - if ( GetTaskQueue16( teb->htask16 ) == oldQueue ) - SetTaskQueue16( teb->htask16, hQueue ); - } - - return oldQueue; -} - -/*********************************************************************** - * GetThreadQueue (KERNEL.464) - */ -HQUEUE16 WINAPI GetThreadQueue16( DWORD thread ) -{ - TEB *teb = NULL; - if ( !thread ) - teb = NtCurrentTeb(); - else if ( HIWORD(thread) ) - teb = THREAD_IdToTEB( thread ); - else if ( IsTask16( (HTASK16)thread ) ) - teb = (TASK_GetPtr( (HANDLE16)thread ))->teb; - - return (HQUEUE16)(teb? teb->queue : 0); -} - -/*********************************************************************** - * SetFastQueue (KERNEL.624) - */ -VOID WINAPI SetFastQueue16( DWORD thread, HQUEUE16 hQueue ) -{ - TEB *teb = NULL; - if ( !thread ) - teb = NtCurrentTeb(); - else if ( HIWORD(thread) ) - teb = THREAD_IdToTEB( thread ); - else if ( IsTask16( (HTASK16)thread ) ) - teb = (TASK_GetPtr( (HANDLE16)thread ))->teb; - - if ( teb ) teb->queue = hQueue; -} - -/*********************************************************************** - * GetFastQueue (KERNEL.625) - */ -HQUEUE16 WINAPI GetFastQueue16( void ) -{ - HQUEUE16 ret = NtCurrentTeb()->queue; - - if (!ret) FIXME("(): should initialize thread-local queue, expect failure!\n" ); - return ret; -} - -/*********************************************************************** - * SwitchStackTo (KERNEL.108) - */ -void WINAPI SwitchStackTo16( WORD seg, WORD ptr, WORD top ) -{ - TDB *pTask; - STACK16FRAME *oldFrame, *newFrame; - INSTANCEDATA *pData; - UINT16 copySize; - - if (!(pTask = TASK_GetCurrent())) return; - if (!(pData = (INSTANCEDATA *)GlobalLock16( seg ))) return; - TRACE("old=%04x:%04x new=%04x:%04x\n", - SELECTOROF( pTask->teb->cur_stack ), - OFFSETOF( pTask->teb->cur_stack ), seg, ptr ); - - /* Save the old stack */ - - oldFrame = THREAD_STACK16( pTask->teb ); - /* pop frame + args and push bp */ - pData->old_ss_sp = pTask->teb->cur_stack + sizeof(STACK16FRAME) - + 2 * sizeof(WORD); - *(WORD *)MapSL(pData->old_ss_sp) = oldFrame->bp; - pData->stacktop = top; - pData->stackmin = ptr; - pData->stackbottom = ptr; - - /* Switch to the new stack */ - - /* Note: we need to take the 3 arguments into account; otherwise, - * the stack will underflow upon return from this function. - */ - copySize = oldFrame->bp - OFFSETOF(pData->old_ss_sp); - copySize += 3 * sizeof(WORD) + sizeof(STACK16FRAME); - pTask->teb->cur_stack = MAKESEGPTR( seg, ptr - copySize ); - newFrame = THREAD_STACK16( pTask->teb ); - - /* Copy the stack frame and the local variables to the new stack */ - - memmove( newFrame, oldFrame, copySize ); - newFrame->bp = ptr; - *(WORD *)MapSL( MAKESEGPTR( seg, ptr ) ) = 0; /* clear previous bp */ -} - - -/*********************************************************************** - * SwitchStackBack (KERNEL.109) - */ -void WINAPI SwitchStackBack16( CONTEXT86 *context ) -{ - STACK16FRAME *oldFrame, *newFrame; - INSTANCEDATA *pData; - - if (!(pData = (INSTANCEDATA *)GlobalLock16(SELECTOROF(NtCurrentTeb()->cur_stack)))) - return; - if (!pData->old_ss_sp) - { - WARN("No previous SwitchStackTo\n" ); - return; - } - TRACE("restoring stack %04x:%04x\n", - SELECTOROF(pData->old_ss_sp), OFFSETOF(pData->old_ss_sp) ); - - oldFrame = CURRENT_STACK16; - - /* Pop bp from the previous stack */ - - context->Ebp = (context->Ebp & ~0xffff) | *(WORD *)MapSL(pData->old_ss_sp); - pData->old_ss_sp += sizeof(WORD); - - /* Switch back to the old stack */ - - NtCurrentTeb()->cur_stack = pData->old_ss_sp - sizeof(STACK16FRAME); - context->SegSs = SELECTOROF(pData->old_ss_sp); - context->Esp = OFFSETOF(pData->old_ss_sp) - sizeof(DWORD); /*ret addr*/ - pData->old_ss_sp = 0; - - /* Build a stack frame for the return */ - - newFrame = CURRENT_STACK16; - newFrame->frame32 = oldFrame->frame32; - newFrame->module_cs = oldFrame->module_cs; - newFrame->callfrom_ip = oldFrame->callfrom_ip; - newFrame->entry_ip = oldFrame->entry_ip; -} - - -/*********************************************************************** - * GetTaskQueueDS (KERNEL.118) - */ -void WINAPI GetTaskQueueDS16(void) -{ - CURRENT_STACK16->ds = GlobalHandleToSel16( GetTaskQueue16(0) ); -} - - -/*********************************************************************** - * GetTaskQueueES (KERNEL.119) - */ -void WINAPI GetTaskQueueES16(void) -{ - CURRENT_STACK16->es = GlobalHandleToSel16( GetTaskQueue16(0) ); -} - - /*********************************************************************** * GetCurrentTask (KERNEL32.@) */ @@ -1174,17 +127,6 @@ HTASK16 WINAPI GetCurrentTask(void) return NtCurrentTeb()->htask16; } -/*********************************************************************** - * GetCurrentTask (KERNEL.36) - */ -DWORD WINAPI WIN16_GetCurrentTask(void) -{ - /* This is the version used by relay code; the first task is */ - /* returned in the high word of the result */ - return MAKELONG( GetCurrentTask(), hFirstTask ); -} - - /*********************************************************************** * GetCurrentPDB (KERNEL.37) * @@ -1199,183 +141,6 @@ DWORD WINAPI GetCurrentPDB16(void) } -/*********************************************************************** - * GetCurPID (KERNEL.157) - */ -DWORD WINAPI GetCurPID16( DWORD unused ) -{ - return 0; -} - - -/*********************************************************************** - * GetInstanceData (KERNEL.54) - */ -INT16 WINAPI GetInstanceData16( HINSTANCE16 instance, WORD buffer, INT16 len ) -{ - char *ptr = (char *)GlobalLock16( instance ); - if (!ptr || !len) return 0; - if ((int)buffer + len >= 0x10000) len = 0x10000 - buffer; - memcpy( (char *)GlobalLock16(CURRENT_DS) + buffer, ptr + buffer, len ); - return len; -} - - -/*********************************************************************** - * GetExeVersion (KERNEL.105) - */ -WORD WINAPI GetExeVersion16(void) -{ - TDB *pTask; - - if (!(pTask = TASK_GetCurrent())) return 0; - return pTask->version; -} - - -/*********************************************************************** - * SetErrorMode (KERNEL.107) - */ -UINT16 WINAPI SetErrorMode16( UINT16 mode ) -{ - TDB *pTask; - if (!(pTask = TASK_GetCurrent())) return 0; - pTask->error_mode = mode; - return SetErrorMode( mode ); -} - - -/*********************************************************************** - * GetNumTasks (KERNEL.152) - */ -UINT16 WINAPI GetNumTasks16(void) -{ - return nTaskCount; -} - - -/*********************************************************************** - * GetTaskDS (KERNEL.155) - * - * Note: this function apparently returns a DWORD with LOWORD == HIWORD. - * I don't think we need to bother with this. - */ -HINSTANCE16 WINAPI GetTaskDS16(void) -{ - TDB *pTask; - - if (!(pTask = TASK_GetCurrent())) return 0; - return GlobalHandleToSel16(pTask->hInstance); -} - -/*********************************************************************** - * GetDummyModuleHandleDS (KERNEL.602) - */ -WORD WINAPI GetDummyModuleHandleDS16(void) -{ - TDB *pTask; - WORD selector; - - if (!(pTask = TASK_GetCurrent())) return 0; - if (!(pTask->flags & TDBF_WIN32)) return 0; - selector = GlobalHandleToSel16( pTask->hModule ); - CURRENT_DS = selector; - return selector; -} - -/*********************************************************************** - * IsTask (KERNEL.320) - */ -BOOL16 WINAPI IsTask16( HTASK16 hTask ) -{ - TDB *pTask; - - if (!(pTask = TASK_GetPtr( hTask ))) return FALSE; - if (GlobalSize16( hTask ) < sizeof(TDB)) return FALSE; - return (pTask->magic == TDB_MAGIC); -} - - -/*********************************************************************** - * IsWinOldApTask (KERNEL.158) - */ -BOOL16 WINAPI IsWinOldApTask16( HTASK16 hTask ) -{ - /* should return bit 0 of byte 0x48 in PSP */ - return FALSE; -} - -/*********************************************************************** - * SetTaskSignalProc (KERNEL.38) - */ -FARPROC16 WINAPI SetTaskSignalProc( HTASK16 hTask, FARPROC16 proc ) -{ - TDB *pTask; - FARPROC16 oldProc; - - if (!hTask) hTask = GetCurrentTask(); - if (!(pTask = TASK_GetPtr( hTask ))) return NULL; - oldProc = pTask->userhandler; - pTask->userhandler = proc; - return oldProc; -} - -/*********************************************************************** - * TASK_CallTaskSignalProc - */ -/* ### start build ### */ -extern WORD CALLBACK TASK_CallTo16_word_wwwww(FARPROC16,WORD,WORD,WORD,WORD,WORD); -/* ### stop build ### */ -void TASK_CallTaskSignalProc( UINT16 uCode, HANDLE16 hTaskOrModule ) -{ - TDB *pTask = TASK_GetCurrent(); - if ( !pTask || !pTask->userhandler ) return; - - TASK_CallTo16_word_wwwww( pTask->userhandler, - hTaskOrModule, uCode, 0, - pTask->hInstance, pTask->hQueue ); -} - -/*********************************************************************** - * SetSigHandler (KERNEL.140) - */ -WORD WINAPI SetSigHandler16( FARPROC16 newhandler, FARPROC16* oldhandler, - UINT16 *oldmode, UINT16 newmode, UINT16 flag ) -{ - FIXME("(%p,%p,%p,%d,%d), unimplemented.\n", - newhandler,oldhandler,oldmode,newmode,flag ); - - if (flag != 1) return 0; - if (!newmode) newhandler = NULL; /* Default handler */ - if (newmode != 4) - { - TDB *pTask; - - if (!(pTask = TASK_GetCurrent())) return 0; - if (oldmode) *oldmode = pTask->signal_flags; - pTask->signal_flags = newmode; - if (oldhandler) *oldhandler = pTask->sighandler; - pTask->sighandler = newhandler; - } - return 0; -} - - -/*********************************************************************** - * GlobalNotify (KERNEL.154) - * - * Note that GlobalNotify does _not_ return the old NotifyProc - * -- contrary to LocalNotify !! - */ -VOID WINAPI GlobalNotify16( FARPROC16 proc ) -{ - TDB *pTask; - - if (!(pTask = TASK_GetCurrent())) return; - pTask->discardhandler = proc; -} - - /*********************************************************************** * GetExePtrHelper */ @@ -1446,136 +211,3 @@ HMODULE16 WINAPI GetExePtr( HANDLE16 handle ) HTASK16 hTask = 0; return GetExePtrHelper( handle, &hTask ); } - - -/*********************************************************************** - * TaskFirst (TOOLHELP.63) - */ -BOOL16 WINAPI TaskFirst16( TASKENTRY *lpte ) -{ - lpte->hNext = hFirstTask; - return TaskNext16( lpte ); -} - - -/*********************************************************************** - * TaskNext (TOOLHELP.64) - */ -BOOL16 WINAPI TaskNext16( TASKENTRY *lpte ) -{ - TDB *pTask; - INSTANCEDATA *pInstData; - - TRACE_(toolhelp)("(%p): task=%04x\n", lpte, lpte->hNext ); - if (!lpte->hNext) return FALSE; - - /* make sure that task and hInstance are valid (skip initial Wine task !) */ - while (1) { - pTask = TASK_GetPtr( lpte->hNext ); - if (!pTask || pTask->magic != TDB_MAGIC) return FALSE; - if (pTask->hInstance) - break; - lpte->hNext = pTask->hNext; - } - pInstData = MapSL( MAKESEGPTR( GlobalHandleToSel16(pTask->hInstance), 0 ) ); - lpte->hTask = lpte->hNext; - lpte->hTaskParent = pTask->hParent; - lpte->hInst = pTask->hInstance; - lpte->hModule = pTask->hModule; - lpte->wSS = SELECTOROF( pTask->teb->cur_stack ); - lpte->wSP = OFFSETOF( pTask->teb->cur_stack ); - lpte->wStackTop = pInstData->stacktop; - lpte->wStackMinimum = pInstData->stackmin; - lpte->wStackBottom = pInstData->stackbottom; - lpte->wcEvents = pTask->nEvents; - lpte->hQueue = pTask->hQueue; - lstrcpynA( lpte->szModule, pTask->module_name, sizeof(lpte->szModule) ); - lpte->wPSPOffset = 0x100; /*??*/ - lpte->hNext = pTask->hNext; - return TRUE; -} - - -/*********************************************************************** - * TaskFindHandle (TOOLHELP.65) - */ -BOOL16 WINAPI TaskFindHandle16( TASKENTRY *lpte, HTASK16 hTask ) -{ - lpte->hNext = hTask; - return TaskNext16( lpte ); -} - - -typedef INT (WINAPI *MessageBoxA_funcptr)(HWND hWnd, LPCSTR text, LPCSTR title, UINT type); - -/************************************************************************** - * FatalAppExit (KERNEL.137) - */ -void WINAPI FatalAppExit16( UINT16 action, LPCSTR str ) -{ - TDB *pTask = TASK_GetCurrent(); - - if (!pTask || !(pTask->error_mode & SEM_NOGPFAULTERRORBOX)) - { - HMODULE mod = GetModuleHandleA( "user32.dll" ); - if (mod) - { - MessageBoxA_funcptr pMessageBoxA = (MessageBoxA_funcptr)GetProcAddress( mod, "MessageBoxA" ); - if (pMessageBoxA) - { - pMessageBoxA( 0, str, NULL, MB_SYSTEMMODAL | MB_OK ); - goto done; - } - } - ERR( "%s\n", debugstr_a(str) ); - } - done: - ExitThread(0xff); -} - - -/*********************************************************************** - * TerminateApp (TOOLHELP.77) - * - * See "Undocumented Windows". - */ -void WINAPI TerminateApp16(HTASK16 hTask, WORD wFlags) -{ - if (hTask && hTask != GetCurrentTask()) - { - FIXME("cannot terminate task %x\n", hTask); - return; - } - - if (wFlags & NO_UAE_BOX) - { - UINT16 old_mode; - old_mode = SetErrorMode16(0); - SetErrorMode16(old_mode|SEM_NOGPFAULTERRORBOX); - } - FatalAppExit16( 0, NULL ); - - /* hmm, we're still alive ?? */ - - /* check undocumented flag */ - if (!(wFlags & 0x8000)) - TASK_CallTaskSignalProc( USIG16_TERMINATION, hTask ); - - /* UndocWin says to call int 0x21/0x4c exit=0xff here, - but let's just call ExitThread */ - ExitThread(0xff); -} - - -/*********************************************************************** - * GetAppCompatFlags (KERNEL.354) - */ -DWORD WINAPI GetAppCompatFlags16( HTASK16 hTask ) -{ - TDB *pTask; - - if (!hTask) hTask = GetCurrentTask(); - if (!(pTask=TASK_GetPtr( hTask ))) return 0; - if (GlobalSize16(hTask) < sizeof(TDB)) return 0; - return pTask->compat_flags; -} diff --git a/msdos/int21.c b/msdos/int21.c index 4ca3beb9168..f05b88cb64b 100644 --- a/msdos/int21.c +++ b/msdos/int21.c @@ -148,7 +148,7 @@ static BOOL INT21_CreateHeap(void) static BYTE *GetCurrentDTA( CONTEXT86 *context ) { - TDB *pTask = TASK_GetCurrent(); + TDB *pTask = GlobalLock16(GetCurrentTask()); /* FIXME: This assumes DTA was set correctly! */ return (BYTE *)CTX_SEG_OFF_TO_LIN( context, SELECTOROF(pTask->dta), diff --git a/scheduler/thread.c b/scheduler/thread.c index 414a52daa01..81b2d6dee6c 100644 --- a/scheduler/thread.c +++ b/scheduler/thread.c @@ -35,7 +35,6 @@ #endif #include "wine/winbase16.h" #include "thread.h" -#include "task.h" #include "module.h" #include "winerror.h" #include "selectors.h" @@ -53,39 +52,6 @@ static TEB initial_teb; extern struct _PDB current_process; -/*********************************************************************** - * THREAD_IdToTEB - * - * Convert a thread id to a TEB, making sure it is valid. - */ -TEB *THREAD_IdToTEB( DWORD id ) -{ - TEB *ret = NULL; - - if (!id || id == GetCurrentThreadId()) return NtCurrentTeb(); - - SERVER_START_REQ( get_thread_info ) - { - req->handle = 0; - req->tid_in = id; - if (!wine_server_call( req )) ret = reply->teb; - } - SERVER_END_REQ; - - if (!ret) - { - /* Allow task handles to be used; convert to main thread */ - if ( IsTask16( id ) ) - { - TDB *pTask = TASK_GetPtr( id ); - if (pTask) return pTask->teb; - } - SetLastError( ERROR_INVALID_PARAMETER ); - } - return ret; -} - - /*********************************************************************** * THREAD_InitTEB * @@ -341,7 +307,6 @@ void WINAPI ExitThread( DWORD code ) /* [in] Exit code for this thread */ else { LdrShutdownThread(); - if (!(NtCurrentTeb()->tibflags & TEBF_WIN32)) TASK_ExitTask(); SYSDEPS_ExitThread( code ); } }