Release 980201
[wine.git] / loader / ne_image.c
blobd092b3d85749e37624cf7f89335dc3efa14cc43e
1 /*
2 * NE modules
4 * Copyright 1993 Robert J. Amstadt
5 * Copyright 1995 Alexandre Julliard
6 */
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <sys/types.h>
11 #include <sys/stat.h>
12 #include <fcntl.h>
13 #include <unistd.h>
14 #include <ctype.h>
15 #include <string.h>
16 #include <errno.h>
17 #include "neexe.h"
18 #include "windows.h"
19 #include "global.h"
20 #include "task.h"
21 #include "selectors.h"
22 #include "callback.h"
23 #include "file.h"
24 #include "module.h"
25 #include "stackframe.h"
26 #include "stddebug.h"
27 #include "debug.h"
28 #include "xmalloc.h"
31 /***********************************************************************
32 * NE_LoadSegment
34 BOOL32 NE_LoadSegment( NE_MODULE *pModule, WORD segnum )
36 SEGTABLEENTRY *pSegTable, *pSeg;
37 WORD *pModuleTable;
38 WORD count, i, offset;
39 HMODULE16 module;
40 FARPROC16 address;
41 int fd;
42 struct relocation_entry_s *rep, *reloc_entries;
43 BYTE *func_name;
44 int size;
45 char* mem;
47 char buffer[256];
48 int ordinal, additive;
49 unsigned short *sp;
51 pSegTable = NE_SEG_TABLE( pModule );
52 pSeg = pSegTable + segnum - 1;
53 pModuleTable = NE_MODULE_TABLE( pModule );
55 if (!pSeg->filepos) return TRUE; /* No file image, just return */
57 fd = MODULE_OpenFile( pModule->self );
58 dprintf_module( stddeb, "Loading segment %d, selector=%04x, flags=%04x\n",
59 segnum, pSeg->selector, pSeg->flags );
60 lseek( fd, pSeg->filepos << pModule->alignment, SEEK_SET );
61 if (pSeg->size) size = pSeg->size;
62 else if (pSeg->minsize) size = pSeg->minsize;
63 else size = 0x10000;
64 mem = GlobalLock16(pSeg->selector);
65 if (pModule->flags & NE_FFLAGS_SELFLOAD && segnum > 1)
67 /* Implement self loading segments */
68 SELFLOADHEADER *selfloadheader;
69 STACK16FRAME *stack16Top;
70 DWORD oldstack;
71 WORD oldselector, newselector;
72 THDB *thdb = THREAD_Current();
73 HFILE32 hf = FILE_DupUnixHandle( fd );
75 selfloadheader = (SELFLOADHEADER *)
76 PTR_SEG_OFF_TO_LIN(pSegTable->selector,0);
77 oldstack = thdb->cur_stack;
78 oldselector = pSeg->selector;
79 thdb->cur_stack = PTR_SEG_OFF_TO_SEGPTR(pModule->self_loading_sel,
80 0xff00 - sizeof(*stack16Top));
81 stack16Top = (STACK16FRAME *)PTR_SEG_TO_LIN(thdb->cur_stack);
82 stack16Top->frame32 = 0;
83 stack16Top->ds = stack16Top->es = pModule->self_loading_sel;
84 stack16Top->entry_point = 0;
85 stack16Top->entry_ip = 0;
86 stack16Top->entry_cs = 0;
87 stack16Top->bp = 0;
88 stack16Top->ip = 0;
89 stack16Top->cs = 0;
90 newselector = Callbacks->CallLoadAppSegProc(selfloadheader->LoadAppSeg,
91 pModule->self, hf, segnum );
92 _lclose32( hf );
93 if (newselector != oldselector) {
94 /* Self loaders like creating their own selectors;
95 * they love asking for trouble to Wine developers
97 if (segnum == pModule->dgroup) {
98 memcpy(PTR_SEG_OFF_TO_LIN(oldselector,0),
99 PTR_SEG_OFF_TO_LIN(newselector,0),
100 pSeg->minsize ? pSeg->minsize : 0x10000);
101 FreeSelector(newselector);
102 pSeg->selector = oldselector;
103 fprintf(stderr, "A new selector was allocated for the dgroup segment\n"
104 "Old selector is %d, new one is %d", oldselector, newselector);
105 } else {
106 FreeSelector(pSeg->selector);
107 pSeg->selector = newselector;
111 thdb->cur_stack = oldstack;
113 else if (!(pSeg->flags & NE_SEGFLAGS_ITERATED))
114 read(fd, mem, size);
115 else {
117 The following bit of code for "iterated segments" was written without
118 any documentation on the format of these segments. It seems to work,
119 but may be missing something. If you have any doco please either send
120 it to me or fix the code yourself. gfm@werple.mira.net.au
122 char* buff = xmalloc(size);
123 char* curr = buff;
124 read(fd, buff, size);
125 while(curr < buff + size) {
126 unsigned int rept = *((short*) curr)++;
127 unsigned int len = *((short*) curr)++;
128 for(; rept > 0; rept--) {
129 char* bytes = curr;
130 unsigned int byte;
131 for(byte = 0; byte < len; byte++)
132 *mem++ = *bytes++;
134 curr += len;
136 free(buff);
139 pSeg->flags |= NE_SEGFLAGS_LOADED;
140 if (!(pSeg->flags & NE_SEGFLAGS_RELOC_DATA))
141 return TRUE; /* No relocation data, we are done */
143 read( fd, &count, sizeof(count) );
144 if (!count) return TRUE;
146 dprintf_fixup( stddeb, "Fixups for %*.*s, segment %d, selector %04x\n",
147 *((BYTE *)pModule + pModule->name_table),
148 *((BYTE *)pModule + pModule->name_table),
149 (char *)pModule + pModule->name_table + 1,
150 segnum, pSeg->selector );
152 reloc_entries = (struct relocation_entry_s *)xmalloc(count * sizeof(struct relocation_entry_s));
153 if (read( fd, reloc_entries, count * sizeof(struct relocation_entry_s)) !=
154 count * sizeof(struct relocation_entry_s))
156 dprintf_fixup( stddeb, "Unable to read relocation information\n" );
157 return FALSE;
161 * Go through the relocation table on entry at a time.
163 rep = reloc_entries;
164 for (i = 0; i < count; i++, rep++)
167 * Get the target address corresponding to this entry.
170 /* If additive, there is no target chain list. Instead, add source
171 and target */
172 additive = rep->relocation_type & NE_RELFLAG_ADDITIVE;
173 rep->relocation_type &= 0x3;
175 switch (rep->relocation_type)
177 case NE_RELTYPE_ORDINAL:
178 module = pModuleTable[rep->target1-1];
179 ordinal = rep->target2;
180 address = MODULE_GetEntryPoint( module, ordinal );
181 if (!address)
183 NE_MODULE *pTarget = MODULE_GetPtr( module );
184 if (!pTarget)
185 fprintf( stderr, "Module not found: %04x, reference %d of module %*.*s\n",
186 module, rep->target1,
187 *((BYTE *)pModule + pModule->name_table),
188 *((BYTE *)pModule + pModule->name_table),
189 (char *)pModule + pModule->name_table + 1 );
190 else
191 fprintf( stderr, "Warning: no handler for %*.*s.%d, setting to 0:0\n",
192 *((BYTE *)pTarget + pTarget->name_table),
193 *((BYTE *)pTarget + pTarget->name_table),
194 (char *)pTarget + pTarget->name_table + 1,
195 ordinal );
197 if (debugging_fixup)
199 NE_MODULE *pTarget = MODULE_GetPtr( module );
200 fprintf( stddeb,"%d: %*.*s.%d=%04x:%04x\n", i + 1,
201 *((BYTE *)pTarget + pTarget->name_table),
202 *((BYTE *)pTarget + pTarget->name_table),
203 (char *)pTarget + pTarget->name_table + 1,
204 ordinal, HIWORD(address), LOWORD(address) );
206 break;
208 case NE_RELTYPE_NAME:
209 module = pModuleTable[rep->target1-1];
210 func_name = (char *)pModule + pModule->import_table + rep->target2;
211 memcpy( buffer, func_name+1, *func_name );
212 buffer[*func_name] = '\0';
213 func_name = buffer;
214 ordinal = MODULE_GetOrdinal( module, func_name );
216 address = MODULE_GetEntryPoint( module, ordinal );
218 if (!address)
220 NE_MODULE *pTarget = MODULE_GetPtr( module );
221 fprintf( stderr, "Warning: no handler for %.*s.%s, setting to 0:0\n",
222 *((BYTE *)pTarget + pTarget->name_table),
223 (char *)pTarget + pTarget->name_table + 1, func_name );
225 if (debugging_fixup)
227 NE_MODULE *pTarget = MODULE_GetPtr( module );
228 fprintf( stddeb,"%d: %.*s.%s=%04x:%04x\n", i + 1,
229 *((BYTE *)pTarget + pTarget->name_table),
230 (char *)pTarget + pTarget->name_table + 1,
231 func_name, HIWORD(address), LOWORD(address) );
233 break;
235 case NE_RELTYPE_INTERNAL:
236 if ((rep->target1 & 0xff) == 0xff)
238 address = MODULE_GetEntryPoint( pModule->self, rep->target2 );
240 else
242 address = (FARPROC16)PTR_SEG_OFF_TO_SEGPTR( pSegTable[rep->target1-1].selector, rep->target2 );
245 dprintf_fixup(stddeb,"%d: %04x:%04x\n",
246 i + 1, HIWORD(address), LOWORD(address) );
247 break;
249 case NE_RELTYPE_OSFIXUP:
250 /* Relocation type 7:
252 * These appear to be used as fixups for the Windows
253 * floating point emulator. Let's just ignore them and
254 * try to use the hardware floating point. Linux should
255 * successfully emulate the coprocessor if it doesn't
256 * exist.
258 dprintf_fixup(stddeb,
259 "%d: ADDR TYPE %d, TYPE %d, OFFSET %04x, ",
260 i + 1, rep->address_type, rep->relocation_type,
261 rep->offset);
262 dprintf_fixup(stddeb,"TARGET %04x %04x\n",
263 rep->target1, rep->target2);
264 continue;
266 default:
267 dprintf_fixup(stddeb,
268 "WARNING: %d: ADDR TYPE %d, unknown TYPE %d, OFFSET %04x, ",
269 i + 1, rep->address_type, rep->relocation_type,
270 rep->offset);
271 dprintf_fixup(stddeb,"TARGET %04x %04x\n",
272 rep->target1, rep->target2);
273 free(reloc_entries);
274 return FALSE;
277 offset = rep->offset;
279 /* Apparently, high bit of address_type is sometimes set; */
280 /* we ignore it for now */
281 if (rep->address_type > NE_RADDR_OFFSET32)
282 fprintf( stderr, "WARNING: module %s: unknown reloc addr type = 0x%02x. Please report.\n",
283 MODULE_GetModuleName(pModule->self), rep->address_type );
285 switch (rep->address_type & 0x7f)
287 case NE_RADDR_LOWBYTE:
288 do {
289 sp = PTR_SEG_OFF_TO_LIN( pSeg->selector, offset );
290 dprintf_fixup(stddeb," %04x:%04x:%04x BYTE%s\n",
291 pSeg->selector, offset, *sp, additive ? " additive":"");
292 offset = *sp;
293 if(additive)
294 *(unsigned char*)sp = (unsigned char)(((int)address+offset) & 0xFF);
295 else
296 *(unsigned char*)sp = (unsigned char)((int)address & 0xFF);
298 while (offset != 0xffff && !additive);
299 break;
301 case NE_RADDR_OFFSET16:
302 do {
303 sp = PTR_SEG_OFF_TO_LIN( pSeg->selector, offset );
304 dprintf_fixup(stddeb," %04x:%04x:%04x OFFSET16%s\n",
305 pSeg->selector, offset, *sp, additive ? " additive" : "" );
306 offset = *sp;
307 *sp = LOWORD(address);
308 if (additive) *sp += offset;
310 while (offset != 0xffff && !additive);
311 break;
313 case NE_RADDR_POINTER32:
314 do {
315 sp = PTR_SEG_OFF_TO_LIN( pSeg->selector, offset );
316 dprintf_fixup(stddeb," %04x:%04x:%04x POINTER32%s\n",
317 pSeg->selector, offset, *sp, additive ? " additive" : "" );
318 offset = *sp;
319 *sp = LOWORD(address);
320 if (additive) *sp += offset;
321 *(sp+1) = HIWORD(address);
323 while (offset != 0xffff && !additive);
324 break;
326 case NE_RADDR_SELECTOR:
327 do {
328 sp = PTR_SEG_OFF_TO_LIN( pSeg->selector, offset );
329 dprintf_fixup(stddeb," %04x:%04x:%04x SELECTOR%s\n",
330 pSeg->selector, offset, *sp, additive ? " additive" : "" );
331 offset = *sp;
332 *sp = HIWORD(address);
333 /* Borland creates additive records with offset zero. Strange, but OK */
334 if(additive && offset)
335 fprintf(stderr,"Additive selector to %4.4x.Please report\n",offset);
337 /* FIXME: Quicken 5 has a zero offset fixup. This seems to work */
338 while (offset && offset != 0xffff && !additive);
339 break;
341 default:
342 dprintf_fixup(stddeb,
343 "WARNING: %d: unknown ADDR TYPE %d, TYPE %d, OFFSET %04x, ",
344 i + 1, rep->address_type, rep->relocation_type,
345 rep->offset);
346 dprintf_fixup(stddeb,
347 "TARGET %04x %04x\n", rep->target1, rep->target2);
348 free(reloc_entries);
349 return FALSE;
353 free(reloc_entries);
354 return TRUE;
358 /***********************************************************************
359 * NE_LoadAllSegments
361 BOOL32 NE_LoadAllSegments( NE_MODULE *pModule )
363 int i;
365 if (pModule->flags & NE_FFLAGS_SELFLOAD)
367 HFILE32 hf;
368 /* Handle self loading modules */
369 SEGTABLEENTRY * pSegTable = (SEGTABLEENTRY *) NE_SEG_TABLE(pModule);
370 SELFLOADHEADER *selfloadheader;
371 STACK16FRAME *stack16Top;
372 THDB *thdb = THREAD_Current();
373 HMODULE16 hselfload = GetModuleHandle16("WPROCS");
374 DWORD oldstack;
375 WORD saved_dgroup = pSegTable[pModule->dgroup - 1].selector;
377 dprintf_module(stddeb, "MODULE_Load: %.*s is a self-loading module!\n",
378 *((BYTE*)pModule + pModule->name_table),
379 (char *)pModule + pModule->name_table + 1);
380 if (!NE_LoadSegment( pModule, 1 )) return FALSE;
381 selfloadheader = (SELFLOADHEADER *)
382 PTR_SEG_OFF_TO_LIN(pSegTable->selector, 0);
383 selfloadheader->EntryAddrProc = MODULE_GetEntryPoint(hselfload,27);
384 selfloadheader->MyAlloc = MODULE_GetEntryPoint(hselfload,28);
385 selfloadheader->SetOwner = MODULE_GetEntryPoint(GetModuleHandle16("KERNEL"),403);
386 pModule->self_loading_sel = GlobalHandleToSel(GLOBAL_Alloc(GMEM_ZEROINIT, 0xFF00, pModule->self, FALSE, FALSE, FALSE));
387 oldstack = thdb->cur_stack;
388 thdb->cur_stack = PTR_SEG_OFF_TO_SEGPTR(pModule->self_loading_sel,
389 0xff00 - sizeof(*stack16Top) );
390 stack16Top = (STACK16FRAME *)PTR_SEG_TO_LIN(thdb->cur_stack);
391 stack16Top->frame32 = 0;
392 stack16Top->ebp = 0;
393 stack16Top->ds = stack16Top->es = pModule->self_loading_sel;
394 stack16Top->entry_point = 0;
395 stack16Top->entry_ip = 0;
396 stack16Top->entry_cs = 0;
397 stack16Top->bp = 0;
398 stack16Top->ip = 0;
399 stack16Top->cs = 0;
401 hf = FILE_DupUnixHandle( MODULE_OpenFile( pModule->self ) );
402 Callbacks->CallBootAppProc(selfloadheader->BootApp, pModule->self, hf);
403 _lclose32(hf);
404 /* some BootApp procs overwrite the selector of dgroup */
405 pSegTable[pModule->dgroup - 1].selector = saved_dgroup;
406 thdb->cur_stack = oldstack;
407 for (i = 2; i <= pModule->seg_count; i++)
408 if (!NE_LoadSegment( pModule, i )) return FALSE;
410 else
412 for (i = 1; i <= pModule->seg_count; i++)
413 if (!NE_LoadSegment( pModule, i )) return FALSE;
415 return TRUE;
419 /***********************************************************************
420 * NE_LoadDLLs
422 BOOL32 NE_LoadDLLs( NE_MODULE *pModule )
424 int i;
425 WORD *pModRef = (WORD *)((char *)pModule + pModule->modref_table);
426 WORD *pDLLs = (WORD *)GlobalLock16( pModule->dlls_to_init );
428 for (i = 0; i < pModule->modref_count; i++, pModRef++)
430 char buffer[256];
431 BYTE *pstr = (BYTE *)pModule + pModule->import_table + *pModRef;
432 memcpy( buffer, pstr + 1, *pstr );
433 strcpy( buffer + *pstr, ".dll" );
434 dprintf_module( stddeb, "Loading '%s'\n", buffer );
435 if (!(*pModRef = MODULE_FindModule( buffer )))
437 /* If the DLL is not loaded yet, load it and store */
438 /* its handle in the list of DLLs to initialize. */
439 HMODULE16 hDLL;
441 if ((hDLL = MODULE_Load( buffer, (LPVOID)-1, NE_FFLAGS_IMPLICIT )) == 2)
443 /* file not found */
444 char *p;
446 /* Try with prepending the path of the current module */
447 GetModuleFileName16( pModule->self, buffer, sizeof(buffer) );
448 if (!(p = strrchr( buffer, '\\' ))) p = buffer;
449 memcpy( p + 1, pstr + 1, *pstr );
450 strcpy( p + 1 + *pstr, ".dll" );
451 hDLL = MODULE_Load( buffer, (LPVOID)-1, NE_FFLAGS_IMPLICIT );
453 if (hDLL < 32)
455 /* FIXME: cleanup what was done */
457 fprintf( stderr, "Could not load '%s' required by '%.*s', error = %d\n",
458 buffer, *((BYTE*)pModule + pModule->name_table),
459 (char *)pModule + pModule->name_table + 1, hDLL );
460 return FALSE;
462 *pModRef = MODULE_HANDLEtoHMODULE16( hDLL );
463 *pDLLs++ = *pModRef;
465 else /* Increment the reference count of the DLL */
467 NE_MODULE *pOldDLL = MODULE_GetPtr( *pModRef );
468 if (pOldDLL) pOldDLL->count++;
471 return TRUE;
475 /***********************************************************************
476 * NE_FixupPrologs
478 * Fixup the exported functions prologs.
480 void NE_FixupPrologs( NE_MODULE *pModule )
482 SEGTABLEENTRY *pSegTable;
483 WORD dgroup = 0;
484 WORD sel;
485 BYTE *p, *fixup_ptr, count;
487 pSegTable = NE_SEG_TABLE(pModule);
488 if (pModule->flags & NE_FFLAGS_SINGLEDATA)
489 dgroup = pSegTable[pModule->dgroup-1].selector;
491 dprintf_module( stddeb, "MODULE_FixupPrologs(%04x)\n", pModule->self );
492 p = (BYTE *)pModule + pModule->entry_table;
493 while (*p)
495 if (p[1] == 0) /* Unused entry */
497 p += 2; /* Skip it */
498 continue;
500 if (p[1] == 0xfe) /* Constant entry */
502 p += 2 + *p * 3; /* Skip it */
503 continue;
506 /* Now fixup the entries of this bundle */
507 count = *p;
508 sel = p[1];
509 p += 2;
510 while (count-- > 0)
512 dprintf_module( stddeb,"Flags: %04x, sel %02x ", *p, sel);
513 /* According to the output generated by TDUMP, the flags mean:
514 * 0x0001 function is exported
515 * 0x0002 Single data (seems to occur only in DLLs)
517 if (sel == 0xff) { /* moveable */
518 dprintf_module( stddeb, "(%02x) o %04x ", p[3], *(WORD *)(p+4) );
519 fixup_ptr = (char *)GET_SEL_BASE(pSegTable[p[3]-1].selector) + *(WORD *)(p + 4);
520 } else { /* fixed */
521 dprintf_module( stddeb, "offset %04x ", *(WORD *)(p+1) );
522 fixup_ptr = (char *)GET_SEL_BASE(pSegTable[sel-1].selector) + *(WORD *)(p + 1);
524 dprintf_module( stddeb, "Signature: %02x %02x %02x,ff %x\n",
525 fixup_ptr[0], fixup_ptr[1], fixup_ptr[2],
526 pModule->flags );
527 if (*p & 0x0001)
529 /* Verify the signature */
530 if (((fixup_ptr[0] == 0x1e && fixup_ptr[1] == 0x58)
531 || (fixup_ptr[0] == 0x8c && fixup_ptr[1] == 0xd8))
532 && fixup_ptr[2] == 0x90)
534 if (*p & 0x0002)
536 if (pModule->flags & NE_FFLAGS_MULTIPLEDATA)
538 /* can this happen? */
539 fprintf( stderr, "FixupPrologs got confused\n" );
541 else if (pModule->flags & NE_FFLAGS_SINGLEDATA)
543 *fixup_ptr = 0xb8; /* MOV AX, */
544 *(WORD *)(fixup_ptr+1) = dgroup;
547 else
549 if (pModule->flags & NE_FFLAGS_MULTIPLEDATA) {
550 fixup_ptr[0] = 0x90; /* non-library: NOPs */
551 fixup_ptr[1] = 0x90;
552 fixup_ptr[2] = 0x90;
555 } else {
556 dprintf_fixup( stddeb, "Unknown signature\n" );
559 else
560 dprintf_module( stddeb,"\n");
561 p += (sel == 0xff) ? 6 : 3;
567 /***********************************************************************
568 * NE_InitDLL
570 * Call the DLL initialization code
572 static BOOL32 NE_InitDLL( TDB* pTask, HMODULE16 hModule )
574 NE_MODULE *pModule;
575 SEGTABLEENTRY *pSegTable;
576 CONTEXT context;
578 /* Registers at initialization must be:
579 * cx heap size
580 * di library instance
581 * ds data segment if any
582 * es:si command line (always 0)
585 if (!(pModule = MODULE_GetPtr( hModule ))) return FALSE;
586 pSegTable = NE_SEG_TABLE( pModule );
588 if (!(pModule->flags & NE_FFLAGS_LIBMODULE) ||
589 (pModule->flags & NE_FFLAGS_WIN32)) return TRUE; /*not a library*/
591 /* Call USER signal handler. This is necessary to install a
592 * proper loader for HICON and HCURSOR resources that this DLL
593 * may contain. InitApp() does this for task modules. */
595 if (pTask && pTask->userhandler)
597 pTask->userhandler( hModule, USIG_DLL_LOAD, 0, pTask->hInstance,
598 pTask->hQueue );
601 if (!pModule->cs) return TRUE; /* no initialization code */
603 memset( &context, 0, sizeof(context) );
605 if (!(pModule->flags & NE_FFLAGS_SINGLEDATA))
607 if (pModule->flags & NE_FFLAGS_MULTIPLEDATA || pModule->dgroup)
609 /* Not SINGLEDATA */
610 fprintf(stderr, "Library is not marked SINGLEDATA\n");
611 exit(1);
613 else /* DATA NONE DLL */
615 DS_reg(&context) = 0;
616 ECX_reg(&context) = 0;
619 else /* DATA SINGLE DLL */
621 DS_reg(&context) = pSegTable[pModule->dgroup-1].selector;
622 ECX_reg(&context) = pModule->heap_size;
625 CS_reg(&context) = pSegTable[pModule->cs-1].selector;
626 EIP_reg(&context) = pModule->ip;
627 EBP_reg(&context) = OFFSETOF(THREAD_Current()->cur_stack)
628 + (WORD)&((STACK16FRAME*)0)->bp;
629 EDI_reg(&context) = DS_reg(&context) ? DS_reg(&context) : hModule;
632 pModule->cs = 0; /* Don't initialize it twice */
633 dprintf_dll( stddeb, "Calling LibMain, cs:ip=%04lx:%04x ds=%04lx di=%04x cx=%04x\n",
634 CS_reg(&context), IP_reg(&context), DS_reg(&context),
635 DI_reg(&context), CX_reg(&context) );
636 Callbacks->CallRegisterShortProc( &context, 0 );
637 return TRUE;
641 /***********************************************************************
642 * NE_InitializeDLLs
644 * Recursively initialize all DLLs (according to the order in which
645 * they where loaded).
647 void NE_InitializeDLLs( HMODULE16 hModule )
649 TDB* pTask = (TDB*)GlobalLock16(GetCurrentTask());
650 NE_MODULE *pModule;
651 HMODULE16 *pDLL;
653 if (!(pModule = MODULE_GetPtr( hModule ))) return;
654 if (pModule->flags & NE_FFLAGS_WIN32) return;
656 if (pModule->dlls_to_init)
658 HGLOBAL16 to_init = pModule->dlls_to_init;
659 pModule->dlls_to_init = 0;
660 for (pDLL = (HMODULE16 *)GlobalLock16( to_init ); *pDLL; pDLL++)
662 NE_InitializeDLLs( *pDLL );
664 GlobalFree16( to_init );
666 NE_InitDLL( pTask, hModule );
670 /***********************************************************************
671 * PatchCodeHandle
673 * Needed for self-loading modules.
676 /* It does nothing */
677 void WINAPI PatchCodeHandle(HANDLE16 hSel)
679 fprintf(stderr,"PatchCodeHandle(%04x),stub!\n",hSel);