Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
W
wine-cw
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
wine
wine-cw
Commits
5fbb446c
Commit
5fbb446c
authored
Aug 23, 2003
by
Alexandre Julliard
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Moved most of the 16-bit task support and NE module loader to
dlls/kernel.
parent
df167d17
Hide whitespace changes
Inline
Side-by-side
Showing
16 changed files
with
3445 additions
and
3258 deletions
+3445
-3258
Makefile.in
dlls/kernel/Makefile.in
+3
-0
kernel_main.c
dlls/kernel/kernel_main.c
+1
-0
ne_module.c
dlls/kernel/ne_module.c
+1716
-0
ne_segment.c
dlls/kernel/ne_segment.c
+12
-7
task.c
dlls/kernel/task.c
+1556
-0
thunk.c
dlls/kernel/thunk.c
+2
-2
wowthunk.c
dlls/kernel/wowthunk.c
+2
-2
Makefile.in
dlls/ntdll/Makefile.in
+1
-2
drive.c
files/drive.c
+5
-5
task.h
include/task.h
+1
-3
thread.h
include/thread.h
+0
-1
module.c
loader/module.c
+0
-21
module.c
loader/ne/module.c
+122
-1788
task.c
loader/task.c
+23
-1391
int21.c
msdos/int21.c
+1
-1
thread.c
scheduler/thread.c
+0
-35
No files found.
dlls/kernel/Makefile.in
View file @
5fbb446c
...
...
@@ -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
\
...
...
dlls/kernel/kernel_main.c
View file @
5fbb446c
...
...
@@ -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
();
}
...
...
dlls/kernel/ne_module.c
0 → 100644
View file @
5fbb446c
/*
* 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 <assert.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#include <ctype.h>
#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 !!!
\n
entry: %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
,
&
params
);
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
);
}
loader/ne/
segment.c
→
dlls/kernel/ne_
segment.c
View file @
5fbb446c
...
...
@@ -34,6 +34,7 @@
#include <string.h>
#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
;
...
...
dlls/kernel/task.c
0 → 100644
View file @
5fbb446c
/*
* 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 <stdlib.h>
#include <string.h>
#include <assert.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#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
;
}
dlls/kernel/thunk.c
View file @
5fbb446c
...
...
@@ -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
)
))
)
...
...
dlls/kernel/wowthunk.c
View file @
5fbb446c
...
...
@@ -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
T
HREAD_IdToTEB
((
DWORD
)
handle
)
->
htask16
;
return
T
ASK_GetTaskFromThread
(
(
DWORD
)
handle
)
;
default:
ERR
(
"handle %p of unknown type %d
\n
"
,
handle
,
type
);
...
...
dlls/ntdll/Makefile.in
View file @
5fbb446c
...
...
@@ -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
...
...
files/drive.c
View file @
5fbb446c
...
...
@@ -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
]
=
':'
;
...
...
include/task.h
View file @
5fbb446c
...
...
@@ -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 */
include/thread.h
View file @
5fbb446c
...
...
@@ -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
);
...
...
loader/module.c
View file @
5fbb446c
...
...
@@ -782,27 +782,6 @@ VOID WINAPI FreeLibraryAndExitThread(HINSTANCE hLibModule, DWORD 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.@)
*/
FARPROC
WINAPI
GetProcAddress
(
HMODULE
hModule
,
LPCSTR
function
)
...
...
loader/ne/module.c
View file @
5fbb446c
...
...
@@ -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
*/
...
...
@@ -358,18 +171,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
*/
FARPROC16
WINAPI
NE_GetEntryPoint
(
HMODULE16
hModule
,
WORD
ordinal
)
...
...
@@ -417,1394 +218,178 @@ FARPROC16 NE_GetEntryPointEx( HMODULE16 hModule, WORD ordinal, BOOL16 snoop )
}
/***********************************************************************
* NE_SetEntryPoint
/**********************************************************************
* GetModuleFileName (KERNEL.49)
*
* Comment: see GetModuleFileNameA
*
*
Change the value of an entry point. Use with caution!
*
It can only change the offset value, not the selector
.
*
Even if invoked by second instance of a program,
*
it still returns path of first one
.
*/
BOOL16
NE_SetEntryPoint
(
HMODULE16
hModule
,
WORD
ordinal
,
WORD
offset
)
INT16
WINAPI
GetModuleFileName16
(
HINSTANCE16
hModule
,
LPSTR
lpFileName
,
INT16
nSize
)
{
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
++
;
/* Win95 does not query hModule if set to 0 !
* Is this wrong or maybe Win3.1 only ? */
if
(
!
hModule
)
hModule
=
GetCurrentTask
()
;
memcpy
(
&
entry
->
offs
,
&
offset
,
sizeof
(
WORD
)
);
return
TRUE
;
if
(
!
(
pModule
=
NE_GetPtr
(
hModule
)))
return
0
;
lstrcpynA
(
lpFileName
,
NE_MODULE_NAME
(
pModule
),
nSize
);
if
(
pModule
->
expected_version
>=
0x400
)
GetLongPathNameA
(
NE_MODULE_NAME
(
pModule
),
lpFileName
,
nSize
);
TRACE
(
"%04x -> '%s'
\n
"
,
hModule
,
lpFileName
);
return
strlen
(
lpFileName
);
}
/***********************************************************************
*
NE_OpenFile
*
GetModuleHandle16 (KERNEL32.@)
*/
H
ANDLE
NE_OpenFile
(
NE_MODULE
*
pModul
e
)
H
MODULE16
WINAPI
GetModuleHandle16
(
LPCSTR
nam
e
)
{
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
;
}
HMODULE16
hModule
=
hFirstModule
;
LPSTR
s
;
BYTE
len
,
*
name_table
;
char
tmpstr
[
MAX_PATH
];
NE_MODULE
*
pModule
;
/* wrapper for SetFilePointer and ReadFile */
static
BOOL
read_data
(
HANDLE
handle
,
LONG
offset
,
void
*
buffer
,
DWORD
size
)
{
DWORD
result
;
TRACE
(
"(%s)
\n
"
,
name
);
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
);
}
if
(
!
HIWORD
(
name
))
return
GetExePtr
(
LOWORD
(
name
));
/***********************************************************************
* 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
;
}
}
}
len
=
strlen
(
name
);
if
(
!
len
)
return
0
;
/* Get the segment table */
lstrcpynA
(
tmpstr
,
name
,
sizeof
(
tmpstr
));
pModule
->
seg_table
=
pData
-
(
BYTE
*
)
pModule
;
buffer
=
HeapAlloc
(
GetProcessHeap
(),
0
,
ne_header
.
ne_cseg
*
sizeof
(
struct
ne_segment_table_entry_s
));
if
(
buffer
)
/* If 'name' matches exactly the module name of a module:
* Return its handle.
*/
for
(
hModule
=
hFirstModule
;
hModule
;
hModule
=
pModule
->
next
)
{
int
i
;
struct
ne_segment_table_entry_s
*
pSeg
;
pModule
=
NE_GetPtr
(
hModule
);
if
(
!
pModule
)
break
;
if
(
pModule
->
flags
&
NE_FFLAGS_WIN32
)
continue
;
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 */
name_table
=
(
BYTE
*
)
pModule
+
pModule
->
name_table
;
if
((
*
name_table
==
len
)
&&
!
strncmp
(
name
,
name_table
+
1
,
len
))
return
hModule
;
}
/* Get the resource table */
/* If uppercased 'name' matches exactly the module name of a module:
* Return its handle
*/
for
(
s
=
tmpstr
;
*
s
;
s
++
)
*
s
=
FILE_toupper
(
*
s
);
if
(
ne_header
.
ne_rsrctab
<
ne_header
.
ne_restab
)
for
(
hModule
=
hFirstModule
;
hModule
;
hModule
=
pModule
->
next
)
{
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
=
NE_GetPtr
(
hModule
);
if
(
!
pModule
)
break
;
if
(
pModule
->
flags
&
NE_FFLAGS_WIN32
)
continue
;
pModule
->
name_table
=
pData
-
(
BYTE
*
)
pModu
le
;
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 */
name_table
=
(
BYTE
*
)
pModule
+
pModule
->
name_tab
le
;
/* FIXME: the strncasecmp is WRONG. It should not be case insensitive
,
* but case sensitive! (Unfortunately Winword 6 and subdlls have
* lowercased module names, but try to load uppercase DLLs, so this
* 'i' compare is just a quickfix until the loader handles that
* correctly. -MM 990705
*/
if
((
*
name_table
==
len
)
&&
!
FILE_strncasecmp
(
tmpstr
,
name_table
+
1
,
len
))
return
hModule
;
}
pData
+=
ne_header
.
ne_modtab
-
ne_header
.
ne_restab
;
/* Get the module references table */
/* If the base filename of 'name' matches the base filename of the module
* filename of some module (case-insensitive compare):
* Return its handle.
*/
if
(
ne_header
.
ne_cmod
>
0
)
/* basename: search backwards in passed name to \ / or : */
s
=
tmpstr
+
strlen
(
tmpstr
);
while
(
s
>
tmpstr
)
{
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
);
if
(
s
[
-
1
]
==
'/'
||
s
[
-
1
]
==
'\\'
||
s
[
-
1
]
==
':'
)
break
;
s
--
;
}
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
))
/* search this in loaded filename list */
for
(
hModule
=
hFirstModule
;
hModule
;
hModule
=
pModule
->
next
)
{
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 */
char
*
loadedfn
;
OFSTRUCT
*
ofs
;
if
((
pTempEntryTable
=
HeapAlloc
(
GetProcessHeap
(),
0
,
ne_header
.
ne_cbenttab
))
!=
NULL
)
{
BYTE
nr_entries
,
type
,
*
s
;
pModule
=
NE_GetPtr
(
hModule
);
if
(
!
pModule
)
break
;
if
(
!
pModule
->
fileinfo
)
continue
;
if
(
pModule
->
flags
&
NE_FFLAGS_WIN32
)
continue
;
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 */
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
;
}
return
0
;
}
s
=
pTempEntryTable
;
TRACE
(
"entry table: offs %04x, len %04x, entries %d
\n
"
,
ne_header
.
ne_enttab
,
ne_header
.
ne_cbenttab
,
*
s
);
/***********************************************************************
* GetProcAddress (KERNEL.50)
*/
FARPROC16
WINAPI
GetProcAddress16
(
HMODULE16
hModule
,
LPCSTR
name
)
{
WORD
ordinal
;
FARPROC16
ret
;
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
);
if
(
!
hModule
)
hModule
=
GetCurrentTask
();
hModule
=
GetExePtr
(
hModule
);
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
(
HIWORD
(
name
)
!=
0
)
{
if
(
fastload
)
HeapFree
(
GetProcessHeap
(),
0
,
fastload
);
GlobalFree16
(
hModule
);
return
(
HMODULE16
)
11
;
/* invalid exe */
ordinal
=
NE_GetOrdinal
(
hModule
,
name
);
TRACE
(
"%04x '%s'
\n
"
,
hModule
,
name
);
}
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 !!!
\n
entry: %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
)
else
{
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 */
}
ordinal
=
LOWORD
(
name
);
TRACE
(
"%04x %04x
\n
"
,
hModule
,
ordinal
);
}
else
pModule
->
nrname_handle
=
0
;
/* Allocate a segment for the implicitly-loaded DLLs */
if
(
!
ordinal
)
return
(
FARPROC16
)
0
;
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
;
ret
=
NE_GetEntryPoint
(
hModule
,
ordinal
);
NE_RegisterModule
(
pModule
);
SNOOP16_RegisterDLL
(
pModule
,
path
);
return
hModule
;
TRACE
(
"returning %08x
\n
"
,
(
UINT
)
ret
);
return
ret
;
}
/***********************************************************************
* NE_LoadDLLs
*
* Load all DLLs implicitly linked to a module.
/***************************************************************************
* HasGPHandler (KERNEL.338)
*/
static
BOOL
NE_LoadDLLs
(
NE_MODULE
*
pModule
)
SEGPTR
WINAPI
HasGPHandler16
(
SEGPTR
address
)
{
int
i
;
WORD
*
pModRef
=
(
WORD
*
)((
char
*
)
pModule
+
pModule
->
modref_table
);
WORD
*
pDLLs
=
(
WORD
*
)
GlobalLock16
(
pModule
->
dlls_to_init
);
HMODULE16
hModule
;
int
gpOrdinal
;
SEGPTR
gpPtr
;
GPHANDLERDEF
*
gpHandler
;
for
(
i
=
0
;
i
<
pModule
->
modref_count
;
i
++
,
pModRef
++
)
if
(
(
hModule
=
FarGetOwner16
(
SELECTOROF
(
address
)
))
!=
0
&&
(
gpOrdinal
=
NE_GetOrdinal
(
hModule
,
"__GP"
))
!=
0
&&
(
gpPtr
=
(
SEGPTR
)
NE_GetEntryPointEx
(
hModule
,
gpOrdinal
,
FALSE
))
!=
0
&&
!
IsBadReadPtr16
(
gpPtr
,
sizeof
(
GPHANDLERDEF
)
)
&&
(
gpHandler
=
MapSL
(
gpPtr
))
!=
NULL
)
{
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)
*
* Comment: see GetModuleFileNameA
*
* Even if invoked by second instance of a program,
* it still returns path of first one.
*/
INT16
WINAPI
GetModuleFileName16
(
HINSTANCE16
hModule
,
LPSTR
lpFileName
,
INT16
nSize
)
{
NE_MODULE
*
pModule
;
/* Win95 does not query hModule if set to 0 !
* Is this wrong or maybe Win3.1 only ? */
if
(
!
hModule
)
hModule
=
GetCurrentTask
();
if
(
!
(
pModule
=
NE_GetPtr
(
hModule
)))
return
0
;
lstrcpynA
(
lpFileName
,
NE_MODULE_NAME
(
pModule
),
nSize
);
if
(
pModule
->
expected_version
>=
0x400
)
GetLongPathNameA
(
NE_MODULE_NAME
(
pModule
),
lpFileName
,
nSize
);
TRACE
(
"%04x -> '%s'
\n
"
,
hModule
,
lpFileName
);
return
strlen
(
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
,
&
params
);
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.@)
*/
HMODULE16
WINAPI
GetModuleHandle16
(
LPCSTR
name
)
{
HMODULE16
hModule
=
hFirstModule
;
LPSTR
s
;
BYTE
len
,
*
name_table
;
char
tmpstr
[
MAX_PATH
];
NE_MODULE
*
pModule
;
TRACE
(
"(%s)
\n
"
,
name
);
if
(
!
HIWORD
(
name
))
return
GetExePtr
(
LOWORD
(
name
));
len
=
strlen
(
name
);
if
(
!
len
)
return
0
;
lstrcpynA
(
tmpstr
,
name
,
sizeof
(
tmpstr
));
/* If 'name' matches exactly the module name of a module:
* Return its handle.
*/
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
)
&&
!
strncmp
(
name
,
name_table
+
1
,
len
))
return
hModule
;
}
/* If uppercased 'name' matches exactly the module name of a module:
* Return its handle
*/
for
(
s
=
tmpstr
;
*
s
;
s
++
)
*
s
=
FILE_toupper
(
*
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
;
/* FIXME: the strncasecmp is WRONG. It should not be case insensitive,
* but case sensitive! (Unfortunately Winword 6 and subdlls have
* lowercased module names, but try to load uppercase DLLs, so this
* 'i' compare is just a quickfix until the loader handles that
* correctly. -MM 990705
*/
if
((
*
name_table
==
len
)
&&
!
FILE_strncasecmp
(
tmpstr
,
name_table
+
1
,
len
))
return
hModule
;
}
/* 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 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)
*/
FARPROC16
WINAPI
GetProcAddress16
(
HMODULE16
hModule
,
LPCSTR
name
)
{
WORD
ordinal
;
FARPROC16
ret
;
if
(
!
hModule
)
hModule
=
GetCurrentTask
();
hModule
=
GetExePtr
(
hModule
);
if
(
HIWORD
(
name
)
!=
0
)
{
ordinal
=
NE_GetOrdinal
(
hModule
,
name
);
TRACE
(
"%04x '%s'
\n
"
,
hModule
,
name
);
}
else
{
ordinal
=
LOWORD
(
name
);
TRACE
(
"%04x %04x
\n
"
,
hModule
,
ordinal
);
}
if
(
!
ordinal
)
return
(
FARPROC16
)
0
;
ret
=
NE_GetEntryPoint
(
hModule
,
ordinal
);
TRACE
(
"returning %08x
\n
"
,
(
UINT
)
ret
);
return
ret
;
}
/***************************************************************************
* HasGPHandler (KERNEL.338)
*/
SEGPTR
WINAPI
HasGPHandler16
(
SEGPTR
address
)
{
HMODULE16
hModule
;
int
gpOrdinal
;
SEGPTR
gpPtr
;
GPHANDLERDEF
*
gpHandler
;
if
(
(
hModule
=
FarGetOwner16
(
SELECTOROF
(
address
)
))
!=
0
&&
(
gpOrdinal
=
NE_GetOrdinal
(
hModule
,
"__GP"
))
!=
0
&&
(
gpPtr
=
(
SEGPTR
)
NE_GetEntryPointEx
(
hModule
,
gpOrdinal
,
FALSE
))
!=
0
&&
!
IsBadReadPtr16
(
gpPtr
,
sizeof
(
GPHANDLERDEF
)
)
&&
(
gpHandler
=
MapSL
(
gpPtr
))
!=
NULL
)
{
while
(
gpHandler
->
selector
)
while
(
gpHandler
->
selector
)
{
if
(
SELECTOROF
(
address
)
==
gpHandler
->
selector
&&
OFFSETOF
(
address
)
>=
gpHandler
->
rangeStart
...
...
@@ -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
);
}
loader/task.c
View file @
5fbb446c
...
...
@@ -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,1111 +58,67 @@ 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
)
{
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_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)
*/
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
)
{
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)
*
TASK_GetPtr
*/
HQUEUE16
WINAPI
SetThreadQueue16
(
DWORD
thread
,
HQUEUE16
hQueue
)
static
TDB
*
TASK_GetPtr
(
HTASK16
hTask
)
{
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
;
return
GlobalLock16
(
hTask
);
}
/***********************************************************************
* 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)
*
TASK_GetCurrent
*/
VOID
WINAPI
SetFastQueue16
(
DWORD
thread
,
HQUEUE16
hQueue
)
TDB
*
TASK_GetCurrent
(
void
)
{
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
;
return
TASK_GetPtr
(
GetCurrentTask
()
);
}
/***********************************************************************
* 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
)
*
PostEvent (KERNEL.31
)
*/
void
WINAPI
SwitchStackTo16
(
WORD
seg
,
WORD
ptr
,
WORD
top
)
void
WINAPI
PostEvent16
(
HTASK16
hTask
)
{
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
(
!
hTask
)
hTask
=
GetCurrentTask
();
if
(
!
(
pTask
=
TASK_GetPtr
(
hTask
)))
return
;
if
(
!
(
pData
=
(
INSTANCEDATA
*
)
GlobalLock16
(
SELECTOROF
(
NtCurrentTeb
()
->
cur_stack
))))
return
;
if
(
!
pData
->
old_ss_sp
)
if
(
pTask
->
flags
&
TDBF_WIN32
)
{
WARN
(
"No previous SwitchStackTo
\n
"
);
FIXME
(
"called for Win32 thread (%04x)!
\n
"
,
pTask
->
teb
->
teb_sel
);
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 */
pTask
->
nEvents
++
;
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
;
if
(
pTask
->
nEvents
==
1
)
NtSetEvent
(
pTask
->
hEvent
,
NULL
);
}
/***********************************************************************
*
GetTaskQueueDS (KERNEL.118
)
*
OldYield (KERNEL.117
)
*/
void
WINAPI
GetTaskQueueDS
16
(
void
)
void
WINAPI
OldYield
16
(
void
)
{
CURRENT_STACK16
->
ds
=
GlobalHandleToSel16
(
GetTaskQueue16
(
0
)
);
}
DWORD
count
;
ReleaseThunkLock
(
&
count
);
RestoreThunkLock
(
count
);
}
/***********************************************************************
*
GetTaskQueueES (KERNEL.119
)
*
DirectedYield (KERNEL.150
)
*/
void
WINAPI
GetTaskQueueES16
(
void
)
void
WINAPI
DirectedYield16
(
HTASK16
hTask
)
{
CURRENT_STACK16
->
es
=
GlobalHandleToSel16
(
GetTaskQueue16
(
0
)
);
OldYield16
(
);
}
/***********************************************************************
* GetCurrentTask (KERNEL32.@)
*/
...
...
@@ -1175,17 +128,6 @@ HTASK16 WINAPI GetCurrentTask(void)
}
/***********************************************************************
* 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
...
...
@@ -1200,183 +142,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
*/
static
inline
HMODULE16
GetExePtrHelper
(
HANDLE16
handle
,
HTASK16
*
hTask
)
...
...
@@ -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
;
}
msdos/int21.c
View file @
5fbb446c
...
...
@@ -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
),
...
...
scheduler/thread.c
View file @
5fbb446c
...
...
@@ -35,7 +35,6 @@
#endif
#include "wine/winbase16.h"
#include "thread.h"
#include "task.h"
#include "module.h"
#include "winerror.h"
#include "selectors.h"
...
...
@@ -54,39 +53,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
*
* Initialization of a newly created TEB.
...
...
@@ -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
);
}
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment