Release 980413
[wine/hacks.git] / loader / ne_image.c
blob5bb108835f89792ba53d28ce614eb03e94fea2c7
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 "debug.h"
27 #include "xmalloc.h"
30 /***********************************************************************
31 * NE_GetRelocAddrName
33 static const char *NE_GetRelocAddrName( BYTE addr_type, int additive )
35 switch(addr_type & 0x7f)
37 case NE_RADDR_LOWBYTE: return additive ? "BYTE add" : "BYTE";
38 case NE_RADDR_OFFSET16: return additive ? "OFFSET16 add" : "OFFSET16";
39 case NE_RADDR_POINTER32: return additive ? "POINTER32 add" : "POINTER32";
40 case NE_RADDR_SELECTOR: return additive ? "SELECTOR add" : "SELECTOR";
41 case NE_RADDR_POINTER48: return additive ? "POINTER48 add" : "POINTER48";
42 case NE_RADDR_OFFSET32: return additive ? "OFFSET32 add" : "OFFSET32";
44 return "???";
48 /***********************************************************************
49 * NE_LoadSegment
51 BOOL32 NE_LoadSegment( NE_MODULE *pModule, WORD segnum )
53 SEGTABLEENTRY *pSegTable, *pSeg;
54 WORD *pModuleTable;
55 WORD count, i, offset, next_offset;
56 HMODULE16 module;
57 FARPROC16 address = 0;
58 int fd;
59 struct relocation_entry_s *rep, *reloc_entries;
60 BYTE *func_name;
61 int size;
62 char* mem;
64 char buffer[256];
65 int ordinal, additive;
66 unsigned short *sp;
68 pSegTable = NE_SEG_TABLE( pModule );
69 pSeg = pSegTable + segnum - 1;
70 pModuleTable = NE_MODULE_TABLE( pModule );
72 if (!pSeg->filepos) return TRUE; /* No file image, just return */
74 fd = MODULE_OpenFile( pModule->self );
75 TRACE(module, "Loading segment %d, selector=%04x, flags=%04x\n",
76 segnum, pSeg->selector, pSeg->flags );
77 lseek( fd, pSeg->filepos << pModule->alignment, SEEK_SET );
78 if (pSeg->size) size = pSeg->size;
79 else if (pSeg->minsize) size = pSeg->minsize;
80 else size = 0x10000;
81 mem = GlobalLock16(pSeg->selector);
82 if (pModule->flags & NE_FFLAGS_SELFLOAD && segnum > 1)
84 /* Implement self loading segments */
85 SELFLOADHEADER *selfloadheader;
86 STACK16FRAME *stack16Top;
87 DWORD oldstack;
88 WORD oldselector, newselector;
89 THDB *thdb = THREAD_Current();
90 HFILE32 hf = FILE_DupUnixHandle( fd );
92 selfloadheader = (SELFLOADHEADER *)
93 PTR_SEG_OFF_TO_LIN(pSegTable->selector,0);
94 oldstack = thdb->cur_stack;
95 oldselector = pSeg->selector;
96 thdb->cur_stack = PTR_SEG_OFF_TO_SEGPTR(pModule->self_loading_sel,
97 0xff00 - sizeof(*stack16Top));
98 stack16Top = (STACK16FRAME *)PTR_SEG_TO_LIN(thdb->cur_stack);
99 stack16Top->frame32 = 0;
100 stack16Top->ds = stack16Top->es = pModule->self_loading_sel;
101 stack16Top->entry_point = 0;
102 stack16Top->entry_ip = 0;
103 stack16Top->entry_cs = 0;
104 stack16Top->bp = 0;
105 stack16Top->ip = 0;
106 stack16Top->cs = 0;
107 newselector = Callbacks->CallLoadAppSegProc(selfloadheader->LoadAppSeg,
108 pModule->self, hf, segnum );
109 _lclose32( hf );
110 if (newselector != oldselector) {
111 /* Self loaders like creating their own selectors;
112 * they love asking for trouble to Wine developers
114 if (segnum == pModule->dgroup) {
115 memcpy(PTR_SEG_OFF_TO_LIN(oldselector,0),
116 PTR_SEG_OFF_TO_LIN(newselector,0),
117 pSeg->minsize ? pSeg->minsize : 0x10000);
118 FreeSelector(newselector);
119 pSeg->selector = oldselector;
120 fprintf(stderr, "A new selector was allocated for the dgroup segment\n"
121 "Old selector is %d, new one is %d", oldselector, newselector);
122 } else {
123 FreeSelector(pSeg->selector);
124 pSeg->selector = newselector;
128 thdb->cur_stack = oldstack;
130 else if (!(pSeg->flags & NE_SEGFLAGS_ITERATED))
131 read(fd, mem, size);
132 else {
134 The following bit of code for "iterated segments" was written without
135 any documentation on the format of these segments. It seems to work,
136 but may be missing something. If you have any doc please either send
137 it to me or fix the code yourself. gfm@werple.mira.net.au
139 char* buff = xmalloc(size);
140 char* curr = buff;
141 read(fd, buff, size);
142 while(curr < buff + size) {
143 unsigned int rept = *((short*) curr)++;
144 unsigned int len = *((short*) curr)++;
145 for(; rept > 0; rept--) {
146 char* bytes = curr;
147 unsigned int byte;
148 for(byte = 0; byte < len; byte++)
149 *mem++ = *bytes++;
151 curr += len;
153 free(buff);
156 pSeg->flags |= NE_SEGFLAGS_LOADED;
157 if (!(pSeg->flags & NE_SEGFLAGS_RELOC_DATA))
158 return TRUE; /* No relocation data, we are done */
160 read( fd, &count, sizeof(count) );
161 if (!count) return TRUE;
163 TRACE(fixup, "Fixups for %*.*s, segment %d, selector %04x\n",
164 *((BYTE *)pModule + pModule->name_table),
165 *((BYTE *)pModule + pModule->name_table),
166 (char *)pModule + pModule->name_table + 1,
167 segnum, pSeg->selector );
169 reloc_entries = (struct relocation_entry_s *)xmalloc(count * sizeof(struct relocation_entry_s));
170 if (read( fd, reloc_entries, count * sizeof(struct relocation_entry_s)) !=
171 count * sizeof(struct relocation_entry_s))
173 WARN(fixup, "Unable to read relocation information\n" );
174 return FALSE;
178 * Go through the relocation table one entry at a time.
180 rep = reloc_entries;
181 for (i = 0; i < count; i++, rep++)
184 * Get the target address corresponding to this entry.
187 /* If additive, there is no target chain list. Instead, add source
188 and target */
189 additive = rep->relocation_type & NE_RELFLAG_ADDITIVE;
190 rep->relocation_type &= 0x3;
192 switch (rep->relocation_type)
194 case NE_RELTYPE_ORDINAL:
195 module = pModuleTable[rep->target1-1];
196 ordinal = rep->target2;
197 address = MODULE_GetEntryPoint( module, ordinal );
198 if (!address)
200 NE_MODULE *pTarget = MODULE_GetPtr( module );
201 if (!pTarget)
202 fprintf( stderr, "Module not found: %04x, reference %d of module %*.*s\n",
203 module, rep->target1,
204 *((BYTE *)pModule + pModule->name_table),
205 *((BYTE *)pModule + pModule->name_table),
206 (char *)pModule + pModule->name_table + 1 );
207 else
208 fprintf( stderr, "Warning: no handler for %.*s.%d, setting to 0:0\n",
209 *((BYTE *)pTarget + pTarget->name_table),
210 (char *)pTarget + pTarget->name_table + 1,
211 ordinal );
213 if (TRACE_ON(fixup))
215 NE_MODULE *pTarget = MODULE_GetPtr( module );
216 TRACE( fixup, "%d: %.*s.%d=%04x:%04x %s\n", i + 1,
217 *((BYTE *)pTarget + pTarget->name_table),
218 (char *)pTarget + pTarget->name_table + 1,
219 ordinal, HIWORD(address), LOWORD(address),
220 NE_GetRelocAddrName( rep->address_type, additive ) );
222 break;
224 case NE_RELTYPE_NAME:
225 module = pModuleTable[rep->target1-1];
226 func_name = (char *)pModule + pModule->import_table + rep->target2;
227 memcpy( buffer, func_name+1, *func_name );
228 buffer[*func_name] = '\0';
229 func_name = buffer;
230 ordinal = MODULE_GetOrdinal( module, func_name );
232 address = MODULE_GetEntryPoint( module, ordinal );
234 if (ERR_ON(fixup) && !address)
236 NE_MODULE *pTarget = MODULE_GetPtr( module );
237 ERR(fixup, "Warning: no handler for %.*s.%s, setting to 0:0\n",
238 *((BYTE *)pTarget + pTarget->name_table),
239 (char *)pTarget + pTarget->name_table + 1, func_name );
241 if (TRACE_ON(fixup))
243 NE_MODULE *pTarget = MODULE_GetPtr( module );
244 TRACE( fixup, "%d: %.*s.%s=%04x:%04x %s\n", i + 1,
245 *((BYTE *)pTarget + pTarget->name_table),
246 (char *)pTarget + pTarget->name_table + 1,
247 func_name, HIWORD(address), LOWORD(address),
248 NE_GetRelocAddrName( rep->address_type, additive ) );
250 break;
252 case NE_RELTYPE_INTERNAL:
253 if ((rep->target1 & 0xff) == 0xff)
255 address = MODULE_GetEntryPoint( pModule->self, rep->target2 );
257 else
259 address = (FARPROC16)PTR_SEG_OFF_TO_SEGPTR( pSegTable[rep->target1-1].selector, rep->target2 );
262 TRACE( fixup,"%d: %04x:%04x %s\n",
263 i + 1, HIWORD(address), LOWORD(address),
264 NE_GetRelocAddrName( rep->address_type, additive ) );
265 break;
267 case NE_RELTYPE_OSFIXUP:
268 /* Relocation type 7:
270 * These appear to be used as fixups for the Windows
271 * floating point emulator. Let's just ignore them and
272 * try to use the hardware floating point. Linux should
273 * successfully emulate the coprocessor if it doesn't
274 * exist.
276 TRACE( fixup, "%d: TYPE %d, OFFSET %04x, TARGET %04x %04x %s\n",
277 i + 1, rep->relocation_type, rep->offset,
278 rep->target1, rep->target2,
279 NE_GetRelocAddrName( rep->address_type, additive ) );
280 continue;
283 offset = rep->offset;
285 /* Apparently, high bit of address_type is sometimes set; */
286 /* we ignore it for now */
287 if (rep->address_type > NE_RADDR_OFFSET32)
288 ERR( fixup, "WARNING: module %s: unknown reloc addr type = 0x%02x. Please report.\n",
289 MODULE_GetModuleName(pModule->self), rep->address_type );
291 if (additive)
293 sp = PTR_SEG_OFF_TO_LIN( pSeg->selector, offset );
294 TRACE( fixup," %04x:%04x\n", offset, *sp );
295 switch (rep->address_type & 0x7f)
297 case NE_RADDR_LOWBYTE:
298 *(BYTE *)sp += LOBYTE((int)address);
299 break;
300 case NE_RADDR_OFFSET16:
301 *sp += LOWORD(address);
302 break;
303 case NE_RADDR_POINTER32:
304 *sp += LOWORD(address);
305 *(sp+1) = HIWORD(address);
306 break;
307 case NE_RADDR_SELECTOR:
308 /* Borland creates additive records with offset zero. Strange, but OK */
309 if (*sp)
310 ERR(fixup,"Additive selector to %04x.Please report\n",*sp);
311 else
312 *sp = HIWORD(address);
313 default:
314 goto unknown;
317 else /* non-additive fixup */
321 sp = PTR_SEG_OFF_TO_LIN( pSeg->selector, offset );
322 next_offset = *sp;
323 TRACE( fixup," %04x:%04x\n", offset, *sp );
324 switch (rep->address_type & 0x7f)
326 case NE_RADDR_LOWBYTE:
327 *(BYTE *)sp = LOBYTE((int)address);
328 break;
329 case NE_RADDR_OFFSET16:
330 *sp = LOWORD(address);
331 break;
332 case NE_RADDR_POINTER32:
333 *(FARPROC16 *)sp = address;
334 break;
335 case NE_RADDR_SELECTOR:
336 *sp = SELECTOROF(address);
337 break;
338 default:
339 goto unknown;
341 if (next_offset == offset) break; /* avoid infinite loop */
342 if (next_offset >= GlobalSize16(pSeg->selector)) break;
343 offset = next_offset;
344 } while (offset && (offset != 0xffff));
348 free(reloc_entries);
349 return TRUE;
351 unknown:
352 WARN(fixup, "WARNING: %d: unknown ADDR TYPE %d, "
353 "TYPE %d, OFFSET %04x, TARGET %04x %04x\n",
354 i + 1, rep->address_type, rep->relocation_type,
355 rep->offset, rep->target1, rep->target2);
356 free(reloc_entries);
357 return FALSE;
361 /***********************************************************************
362 * NE_LoadAllSegments
364 BOOL32 NE_LoadAllSegments( NE_MODULE *pModule )
366 int i;
368 if (pModule->flags & NE_FFLAGS_SELFLOAD)
370 HFILE32 hf;
371 /* Handle self loading modules */
372 SEGTABLEENTRY * pSegTable = (SEGTABLEENTRY *) NE_SEG_TABLE(pModule);
373 SELFLOADHEADER *selfloadheader;
374 STACK16FRAME *stack16Top;
375 THDB *thdb = THREAD_Current();
376 HMODULE16 hselfload = GetModuleHandle16("WPROCS");
377 DWORD oldstack;
378 WORD saved_dgroup = pSegTable[pModule->dgroup - 1].selector;
380 TRACE(module, "%.*s is a self-loading module!\n",
381 *((BYTE*)pModule + pModule->name_table),
382 (char *)pModule + pModule->name_table + 1);
383 if (!NE_LoadSegment( pModule, 1 )) return FALSE;
384 selfloadheader = (SELFLOADHEADER *)
385 PTR_SEG_OFF_TO_LIN(pSegTable->selector, 0);
386 selfloadheader->EntryAddrProc = MODULE_GetEntryPoint(hselfload,27);
387 selfloadheader->MyAlloc = MODULE_GetEntryPoint(hselfload,28);
388 selfloadheader->SetOwner = MODULE_GetEntryPoint(GetModuleHandle16("KERNEL"),403);
389 pModule->self_loading_sel = GlobalHandleToSel(GLOBAL_Alloc(GMEM_ZEROINIT, 0xFF00, pModule->self, FALSE, FALSE, FALSE));
390 oldstack = thdb->cur_stack;
391 thdb->cur_stack = PTR_SEG_OFF_TO_SEGPTR(pModule->self_loading_sel,
392 0xff00 - sizeof(*stack16Top) );
393 stack16Top = (STACK16FRAME *)PTR_SEG_TO_LIN(thdb->cur_stack);
394 stack16Top->frame32 = 0;
395 stack16Top->ebp = 0;
396 stack16Top->ds = stack16Top->es = pModule->self_loading_sel;
397 stack16Top->entry_point = 0;
398 stack16Top->entry_ip = 0;
399 stack16Top->entry_cs = 0;
400 stack16Top->bp = 0;
401 stack16Top->ip = 0;
402 stack16Top->cs = 0;
404 hf = FILE_DupUnixHandle( MODULE_OpenFile( pModule->self ) );
405 Callbacks->CallBootAppProc(selfloadheader->BootApp, pModule->self, hf);
406 _lclose32(hf);
407 /* some BootApp procs overwrite the selector of dgroup */
408 pSegTable[pModule->dgroup - 1].selector = saved_dgroup;
409 thdb->cur_stack = oldstack;
410 for (i = 2; i <= pModule->seg_count; i++)
411 if (!NE_LoadSegment( pModule, i )) return FALSE;
413 else
415 for (i = 1; i <= pModule->seg_count; i++)
416 if (!NE_LoadSegment( pModule, i )) return FALSE;
418 return TRUE;
422 /***********************************************************************
423 * NE_LoadDLLs
425 BOOL32 NE_LoadDLLs( NE_MODULE *pModule )
427 int i;
428 WORD *pModRef = (WORD *)((char *)pModule + pModule->modref_table);
429 WORD *pDLLs = (WORD *)GlobalLock16( pModule->dlls_to_init );
431 for (i = 0; i < pModule->modref_count; i++, pModRef++)
433 char buffer[256];
434 BYTE *pstr = (BYTE *)pModule + pModule->import_table + *pModRef;
435 memcpy( buffer, pstr + 1, *pstr );
436 strcpy( buffer + *pstr, ".dll" );
437 TRACE(module, "Loading '%s'\n", buffer );
438 if (!(*pModRef = MODULE_FindModule( buffer )))
440 /* If the DLL is not loaded yet, load it and store */
441 /* its handle in the list of DLLs to initialize. */
442 HMODULE16 hDLL;
444 if ((hDLL = MODULE_Load( buffer, NE_FFLAGS_IMPLICIT,
445 NULL, NULL, 0 )) == 2)
447 /* file not found */
448 char *p;
450 /* Try with prepending the path of the current module */
451 GetModuleFileName16( pModule->self, buffer, sizeof(buffer) );
452 if (!(p = strrchr( buffer, '\\' ))) p = buffer;
453 memcpy( p + 1, pstr + 1, *pstr );
454 strcpy( p + 1 + *pstr, ".dll" );
455 hDLL = MODULE_Load( buffer, NE_FFLAGS_IMPLICIT, NULL, NULL, 0);
457 if (hDLL < 32)
459 /* FIXME: cleanup what was done */
461 fprintf( stderr, "Could not load '%s' required by '%.*s', error = %d\n",
462 buffer, *((BYTE*)pModule + pModule->name_table),
463 (char *)pModule + pModule->name_table + 1, hDLL );
464 return FALSE;
466 *pModRef = MODULE_HANDLEtoHMODULE16( hDLL );
467 *pDLLs++ = *pModRef;
469 else /* Increment the reference count of the DLL */
471 NE_MODULE *pOldDLL = MODULE_GetPtr( *pModRef );
472 if (pOldDLL) pOldDLL->count++;
475 return TRUE;
479 /***********************************************************************
480 * NE_FixupPrologs
482 * Fixup the exported functions prologs.
484 void NE_FixupPrologs( NE_MODULE *pModule )
486 SEGTABLEENTRY *pSegTable;
487 WORD dgroup = 0;
488 WORD sel;
489 BYTE *p, *fixup_ptr, count;
490 dbg_decl_str(module, 512);
492 pSegTable = NE_SEG_TABLE(pModule);
493 if (pModule->flags & NE_FFLAGS_SINGLEDATA)
494 dgroup = pSegTable[pModule->dgroup-1].selector;
496 TRACE(module, "(%04x)\n", pModule->self );
497 p = (BYTE *)pModule + pModule->entry_table;
498 while (*p)
500 if (p[1] == 0) /* Unused entry */
502 p += 2; /* Skip it */
503 continue;
505 if (p[1] == 0xfe) /* Constant entry */
507 p += 2 + *p * 3; /* Skip it */
508 continue;
511 /* Now fixup the entries of this bundle */
512 count = *p;
513 sel = p[1];
514 p += 2;
515 while (count-- > 0)
517 dbg_reset_str(module);
518 dsprintf(module,"Flags: %04x, sel %02x ", *p, sel);
519 /* According to the output generated by TDUMP, the flags mean:
520 * 0x0001 function is exported
521 * 0x0002 Single data (seems to occur only in DLLs)
523 if (sel == 0xff) { /* moveable */
524 dsprintf(module, "(%02x) o %04x", p[3], *(WORD *)(p+4) );
525 fixup_ptr = (char *)GET_SEL_BASE(pSegTable[p[3]-1].selector) + *(WORD *)(p + 4);
526 } else { /* fixed */
527 dsprintf(module, "offset %04x", *(WORD *)(p+1) );
528 fixup_ptr = (char *)GET_SEL_BASE(pSegTable[sel-1].selector) +
529 *(WORD *)(p + 1);
531 TRACE(module, "%s Signature: %02x %02x %02x,ff %x\n",
532 dbg_str(module), fixup_ptr[0], fixup_ptr[1],
533 fixup_ptr[2], pModule->flags );
534 if (*p & 0x0001)
536 /* Verify the signature */
537 if (((fixup_ptr[0] == 0x1e && fixup_ptr[1] == 0x58)
538 || (fixup_ptr[0] == 0x8c && fixup_ptr[1] == 0xd8))
539 && fixup_ptr[2] == 0x90)
541 if (*p & 0x0002)
543 if (pModule->flags & NE_FFLAGS_MULTIPLEDATA)
545 /* can this happen? */
546 fprintf( stderr, "FixupPrologs got confused\n" );
548 else if (pModule->flags & NE_FFLAGS_SINGLEDATA)
550 *fixup_ptr = 0xb8; /* MOV AX, */
551 *(WORD *)(fixup_ptr+1) = dgroup;
554 else
556 if (pModule->flags & NE_FFLAGS_MULTIPLEDATA) {
557 fixup_ptr[0] = 0x90; /* non-library: NOPs */
558 fixup_ptr[1] = 0x90;
559 fixup_ptr[2] = 0x90;
562 } else {
563 WARN(fixup, "Unknown signature\n" );
566 else
567 TRACE(module,"\n");
568 p += (sel == 0xff) ? 6 : 3;
574 /***********************************************************************
575 * NE_InitDLL
577 * Call the DLL initialization code
579 static BOOL32 NE_InitDLL( TDB* pTask, HMODULE16 hModule )
581 NE_MODULE *pModule;
582 SEGTABLEENTRY *pSegTable;
583 CONTEXT context;
585 /* Registers at initialization must be:
586 * cx heap size
587 * di library instance
588 * ds data segment if any
589 * es:si command line (always 0)
592 if (!(pModule = MODULE_GetPtr( hModule ))) return FALSE;
593 pSegTable = NE_SEG_TABLE( pModule );
595 if (!(pModule->flags & NE_FFLAGS_LIBMODULE) ||
596 (pModule->flags & NE_FFLAGS_WIN32)) return TRUE; /*not a library*/
598 /* Call USER signal handler. This is necessary to install a
599 * proper loader for HICON and HCURSOR resources that this DLL
600 * may contain. InitApp() does this for task modules. */
602 if (pTask && pTask->userhandler)
604 pTask->userhandler( hModule, USIG_DLL_LOAD, 0, pTask->hInstance,
605 pTask->hQueue );
608 if (!pModule->cs) return TRUE; /* no initialization code */
610 memset( &context, 0, sizeof(context) );
612 if (!(pModule->flags & NE_FFLAGS_SINGLEDATA))
614 if (pModule->flags & NE_FFLAGS_MULTIPLEDATA || pModule->dgroup)
616 /* Not SINGLEDATA */
617 fprintf(stderr, "Library is not marked SINGLEDATA\n");
618 exit(1);
620 else /* DATA NONE DLL */
622 DS_reg(&context) = 0;
623 ECX_reg(&context) = 0;
626 else /* DATA SINGLE DLL */
628 if (pModule->dgroup) {
629 DS_reg(&context) = pSegTable[pModule->dgroup-1].selector;
630 ECX_reg(&context) = pModule->heap_size;
632 else /* hmm, DLL has no dgroup,
633 but why has it NE_FFLAGS_SINGLEDATA set ?
634 Buggy DLL compiler ? */
636 DS_reg(&context) = 0;
637 ECX_reg(&context) = 0;
641 CS_reg(&context) = pSegTable[pModule->cs-1].selector;
642 EIP_reg(&context) = pModule->ip;
643 EBP_reg(&context) = OFFSETOF(THREAD_Current()->cur_stack)
644 + (WORD)&((STACK16FRAME*)0)->bp;
645 EDI_reg(&context) = DS_reg(&context) ? DS_reg(&context) : hModule;
648 pModule->cs = 0; /* Don't initialize it twice */
649 TRACE(dll, "Calling LibMain, cs:ip=%04lx:%04x ds=%04lx di=%04x cx=%04x\n",
650 CS_reg(&context), IP_reg(&context), DS_reg(&context),
651 DI_reg(&context), CX_reg(&context) );
652 Callbacks->CallRegisterShortProc( &context, 0 );
653 return TRUE;
657 /***********************************************************************
658 * NE_InitializeDLLs
660 * Recursively initialize all DLLs (according to the order in which
661 * they where loaded).
663 void NE_InitializeDLLs( HMODULE16 hModule )
665 TDB* pTask = (TDB*)GlobalLock16(GetCurrentTask());
666 NE_MODULE *pModule;
667 HMODULE16 *pDLL;
669 if (!(pModule = MODULE_GetPtr( hModule ))) return;
670 if (pModule->flags & NE_FFLAGS_WIN32) return;
672 if (pModule->dlls_to_init)
674 HGLOBAL16 to_init = pModule->dlls_to_init;
675 pModule->dlls_to_init = 0;
676 for (pDLL = (HMODULE16 *)GlobalLock16( to_init ); *pDLL; pDLL++)
678 NE_InitializeDLLs( *pDLL );
680 GlobalFree16( to_init );
682 NE_InitDLL( pTask, hModule );
686 /***********************************************************************
687 * PatchCodeHandle
689 * Needed for self-loading modules.
692 /* It does nothing */
693 void WINAPI PatchCodeHandle(HANDLE16 hSel)
695 fprintf(stderr,"PatchCodeHandle(%04x),stub!\n",hSel);