Release 980329
[wine/multimedia.git] / loader / ne_image.c
blob3f00e221881a2ced0741270d32f0c62c0bec8c38
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_LoadSegment
33 BOOL32 NE_LoadSegment( NE_MODULE *pModule, WORD segnum )
35 SEGTABLEENTRY *pSegTable, *pSeg;
36 WORD *pModuleTable;
37 WORD count, i, offset;
38 HMODULE16 module;
39 FARPROC16 address;
40 int fd;
41 struct relocation_entry_s *rep, *reloc_entries;
42 BYTE *func_name;
43 int size;
44 char* mem;
46 char buffer[256];
47 int ordinal, additive;
48 unsigned short *sp;
50 pSegTable = NE_SEG_TABLE( pModule );
51 pSeg = pSegTable + segnum - 1;
52 pModuleTable = NE_MODULE_TABLE( pModule );
54 if (!pSeg->filepos) return TRUE; /* No file image, just return */
56 fd = MODULE_OpenFile( pModule->self );
57 TRACE(module, "Loading segment %d, selector=%04x, flags=%04x\n",
58 segnum, pSeg->selector, pSeg->flags );
59 lseek( fd, pSeg->filepos << pModule->alignment, SEEK_SET );
60 if (pSeg->size) size = pSeg->size;
61 else if (pSeg->minsize) size = pSeg->minsize;
62 else size = 0x10000;
63 mem = GlobalLock16(pSeg->selector);
64 if (pModule->flags & NE_FFLAGS_SELFLOAD && segnum > 1)
66 /* Implement self loading segments */
67 SELFLOADHEADER *selfloadheader;
68 STACK16FRAME *stack16Top;
69 DWORD oldstack;
70 WORD oldselector, newselector;
71 THDB *thdb = THREAD_Current();
72 HFILE32 hf = FILE_DupUnixHandle( fd );
74 selfloadheader = (SELFLOADHEADER *)
75 PTR_SEG_OFF_TO_LIN(pSegTable->selector,0);
76 oldstack = thdb->cur_stack;
77 oldselector = pSeg->selector;
78 thdb->cur_stack = PTR_SEG_OFF_TO_SEGPTR(pModule->self_loading_sel,
79 0xff00 - sizeof(*stack16Top));
80 stack16Top = (STACK16FRAME *)PTR_SEG_TO_LIN(thdb->cur_stack);
81 stack16Top->frame32 = 0;
82 stack16Top->ds = stack16Top->es = pModule->self_loading_sel;
83 stack16Top->entry_point = 0;
84 stack16Top->entry_ip = 0;
85 stack16Top->entry_cs = 0;
86 stack16Top->bp = 0;
87 stack16Top->ip = 0;
88 stack16Top->cs = 0;
89 newselector = Callbacks->CallLoadAppSegProc(selfloadheader->LoadAppSeg,
90 pModule->self, hf, segnum );
91 _lclose32( hf );
92 if (newselector != oldselector) {
93 /* Self loaders like creating their own selectors;
94 * they love asking for trouble to Wine developers
96 if (segnum == pModule->dgroup) {
97 memcpy(PTR_SEG_OFF_TO_LIN(oldselector,0),
98 PTR_SEG_OFF_TO_LIN(newselector,0),
99 pSeg->minsize ? pSeg->minsize : 0x10000);
100 FreeSelector(newselector);
101 pSeg->selector = oldselector;
102 fprintf(stderr, "A new selector was allocated for the dgroup segment\n"
103 "Old selector is %d, new one is %d", oldselector, newselector);
104 } else {
105 FreeSelector(pSeg->selector);
106 pSeg->selector = newselector;
110 thdb->cur_stack = oldstack;
112 else if (!(pSeg->flags & NE_SEGFLAGS_ITERATED))
113 read(fd, mem, size);
114 else {
116 The following bit of code for "iterated segments" was written without
117 any documentation on the format of these segments. It seems to work,
118 but may be missing something. If you have any doc please either send
119 it to me or fix the code yourself. gfm@werple.mira.net.au
121 char* buff = xmalloc(size);
122 char* curr = buff;
123 read(fd, buff, size);
124 while(curr < buff + size) {
125 unsigned int rept = *((short*) curr)++;
126 unsigned int len = *((short*) curr)++;
127 for(; rept > 0; rept--) {
128 char* bytes = curr;
129 unsigned int byte;
130 for(byte = 0; byte < len; byte++)
131 *mem++ = *bytes++;
133 curr += len;
135 free(buff);
138 pSeg->flags |= NE_SEGFLAGS_LOADED;
139 if (!(pSeg->flags & NE_SEGFLAGS_RELOC_DATA))
140 return TRUE; /* No relocation data, we are done */
142 read( fd, &count, sizeof(count) );
143 if (!count) return TRUE;
145 TRACE(fixup, "Fixups for %*.*s, segment %d, selector %04x\n",
146 *((BYTE *)pModule + pModule->name_table),
147 *((BYTE *)pModule + pModule->name_table),
148 (char *)pModule + pModule->name_table + 1,
149 segnum, pSeg->selector );
151 reloc_entries = (struct relocation_entry_s *)xmalloc(count * sizeof(struct relocation_entry_s));
152 if (read( fd, reloc_entries, count * sizeof(struct relocation_entry_s)) !=
153 count * sizeof(struct relocation_entry_s))
155 WARN(fixup, "Unable to read relocation information\n" );
156 return FALSE;
160 * Go through the relocation table one entry at a time.
162 rep = reloc_entries;
163 for (i = 0; i < count; i++, rep++)
166 * Get the target address corresponding to this entry.
169 /* If additive, there is no target chain list. Instead, add source
170 and target */
171 additive = rep->relocation_type & NE_RELFLAG_ADDITIVE;
172 rep->relocation_type &= 0x3;
174 switch (rep->relocation_type)
176 case NE_RELTYPE_ORDINAL:
177 module = pModuleTable[rep->target1-1];
178 ordinal = rep->target2;
179 address = MODULE_GetEntryPoint( module, ordinal );
180 if (!address)
182 NE_MODULE *pTarget = MODULE_GetPtr( module );
183 if (!pTarget)
184 fprintf( stderr, "Module not found: %04x, reference %d of module %*.*s\n",
185 module, rep->target1,
186 *((BYTE *)pModule + pModule->name_table),
187 *((BYTE *)pModule + pModule->name_table),
188 (char *)pModule + pModule->name_table + 1 );
189 else
190 fprintf( stderr, "Warning: no handler for %*.*s.%d, setting to 0:0\n",
191 *((BYTE *)pTarget + pTarget->name_table),
192 *((BYTE *)pTarget + pTarget->name_table),
193 (char *)pTarget + pTarget->name_table + 1,
194 ordinal );
196 if (TRACE_ON(fixup))
198 NE_MODULE *pTarget = MODULE_GetPtr( module );
199 TRACE(fixup, "%d: %*.*s.%d=%04x:%04x\n", i + 1,
200 *((BYTE *)pTarget + pTarget->name_table),
201 *((BYTE *)pTarget + pTarget->name_table),
202 (char *)pTarget + pTarget->name_table + 1,
203 ordinal, HIWORD(address), LOWORD(address) );
205 break;
207 case NE_RELTYPE_NAME:
208 module = pModuleTable[rep->target1-1];
209 func_name = (char *)pModule + pModule->import_table + rep->target2;
210 memcpy( buffer, func_name+1, *func_name );
211 buffer[*func_name] = '\0';
212 func_name = buffer;
213 ordinal = MODULE_GetOrdinal( module, func_name );
215 address = MODULE_GetEntryPoint( module, ordinal );
217 if (ERR_ON(fixup) && !address)
219 NE_MODULE *pTarget = MODULE_GetPtr( module );
220 ERR(fixup, "Warning: no handler for %.*s.%s, setting to 0:0\n",
221 *((BYTE *)pTarget + pTarget->name_table),
222 (char *)pTarget + pTarget->name_table + 1, func_name );
224 if (TRACE_ON(fixup))
226 NE_MODULE *pTarget = MODULE_GetPtr( module );
227 TRACE(fixup, "%d: %.*s.%s=%04x:%04x\n", i + 1,
228 *((BYTE *)pTarget + pTarget->name_table),
229 (char *)pTarget + pTarget->name_table + 1,
230 func_name, HIWORD(address), LOWORD(address) );
232 break;
234 case NE_RELTYPE_INTERNAL:
235 if ((rep->target1 & 0xff) == 0xff)
237 address = MODULE_GetEntryPoint( pModule->self, rep->target2 );
239 else
241 address = (FARPROC16)PTR_SEG_OFF_TO_SEGPTR( pSegTable[rep->target1-1].selector, rep->target2 );
244 TRACE(fixup,"%d: %04x:%04x\n",
245 i + 1, HIWORD(address), LOWORD(address) );
246 break;
248 case NE_RELTYPE_OSFIXUP:
249 /* Relocation type 7:
251 * These appear to be used as fixups for the Windows
252 * floating point emulator. Let's just ignore them and
253 * try to use the hardware floating point. Linux should
254 * successfully emulate the coprocessor if it doesn't
255 * exist.
257 TRACE(fixup, "%d: ADDR TYPE %d, TYPE %d, OFFSET %04x, "
258 "TARGET %04x %04x\n", i + 1, rep->address_type,
259 rep->relocation_type, rep->offset, rep->target1, rep->target2);
260 continue;
262 default:
263 WARN(fixup, "WARNING: %d: ADDR TYPE %d, "
264 "unknown TYPE %d, OFFSET %04x, TARGET %04x %04x\n",
265 i + 1, rep->address_type, rep->relocation_type,
266 rep->offset, rep->target1, rep->target2);
267 free(reloc_entries);
268 return FALSE;
271 offset = rep->offset;
273 /* Apparently, high bit of address_type is sometimes set; */
274 /* we ignore it for now */
275 if (rep->address_type > NE_RADDR_OFFSET32)
276 fprintf( stderr, "WARNING: module %s: unknown reloc addr type = 0x%02x. Please report.\n",
277 MODULE_GetModuleName(pModule->self), rep->address_type );
279 switch (rep->address_type & 0x7f)
281 case NE_RADDR_LOWBYTE:
282 do {
283 sp = PTR_SEG_OFF_TO_LIN( pSeg->selector, offset );
284 TRACE(fixup," %04x:%04x:%04x BYTE%s\n",
285 pSeg->selector, offset, *sp, additive ? " additive":"");
286 offset = *sp;
287 if(additive)
288 *(unsigned char*)sp = (unsigned char)(((int)address+offset) & 0xFF);
289 else
290 *(unsigned char*)sp = (unsigned char)((int)address & 0xFF);
292 while (offset && offset != 0xffff && !additive);
293 break;
295 case NE_RADDR_OFFSET16:
296 do {
297 sp = PTR_SEG_OFF_TO_LIN( pSeg->selector, offset );
298 TRACE(fixup," %04x:%04x:%04x OFFSET16%s\n",
299 pSeg->selector, offset, *sp, additive ? " additive" : "" );
300 offset = *sp;
301 *sp = LOWORD(address);
302 if (additive) *sp += offset;
304 while (offset && offset != 0xffff && !additive);
305 break;
307 case NE_RADDR_POINTER32:
308 do {
309 sp = PTR_SEG_OFF_TO_LIN( pSeg->selector, offset );
310 TRACE(fixup," %04x:%04x:%04x POINTER32%s\n",
311 pSeg->selector, offset, *sp, additive ? " additive" : "" );
312 offset = *sp;
313 *sp = LOWORD(address);
314 if (additive) *sp += offset;
315 *(sp+1) = HIWORD(address);
317 while (offset && offset != 0xffff && !additive);
318 break;
320 case NE_RADDR_SELECTOR:
321 do {
322 sp = PTR_SEG_OFF_TO_LIN( pSeg->selector, offset );
323 TRACE(fixup," %04x:%04x:%04x SELECTOR%s\n",
324 pSeg->selector, offset, *sp, additive ? " additive" : "" );
325 offset = *sp;
326 *sp = HIWORD(address);
327 /* Borland creates additive records with offset zero. Strange, but OK */
328 if(additive && offset)
329 fprintf(stderr,"Additive selector to %4.4x.Please report\n",offset);
331 while (offset && offset != 0xffff && !additive);
332 break;
334 default:
335 WARN(fixup, "WARNING: %d: unknown ADDR TYPE %d, "
336 "TYPE %d, OFFSET %04x, TARGET %04x %04x\n",
337 i + 1, rep->address_type, rep->relocation_type,
338 rep->offset, rep->target1, rep->target2);
339 free(reloc_entries);
340 return FALSE;
344 free(reloc_entries);
345 return TRUE;
349 /***********************************************************************
350 * NE_LoadAllSegments
352 BOOL32 NE_LoadAllSegments( NE_MODULE *pModule )
354 int i;
356 if (pModule->flags & NE_FFLAGS_SELFLOAD)
358 HFILE32 hf;
359 /* Handle self loading modules */
360 SEGTABLEENTRY * pSegTable = (SEGTABLEENTRY *) NE_SEG_TABLE(pModule);
361 SELFLOADHEADER *selfloadheader;
362 STACK16FRAME *stack16Top;
363 THDB *thdb = THREAD_Current();
364 HMODULE16 hselfload = GetModuleHandle16("WPROCS");
365 DWORD oldstack;
366 WORD saved_dgroup = pSegTable[pModule->dgroup - 1].selector;
368 TRACE(module, "%.*s is a self-loading module!\n",
369 *((BYTE*)pModule + pModule->name_table),
370 (char *)pModule + pModule->name_table + 1);
371 if (!NE_LoadSegment( pModule, 1 )) return FALSE;
372 selfloadheader = (SELFLOADHEADER *)
373 PTR_SEG_OFF_TO_LIN(pSegTable->selector, 0);
374 selfloadheader->EntryAddrProc = MODULE_GetEntryPoint(hselfload,27);
375 selfloadheader->MyAlloc = MODULE_GetEntryPoint(hselfload,28);
376 selfloadheader->SetOwner = MODULE_GetEntryPoint(GetModuleHandle16("KERNEL"),403);
377 pModule->self_loading_sel = GlobalHandleToSel(GLOBAL_Alloc(GMEM_ZEROINIT, 0xFF00, pModule->self, FALSE, FALSE, FALSE));
378 oldstack = thdb->cur_stack;
379 thdb->cur_stack = PTR_SEG_OFF_TO_SEGPTR(pModule->self_loading_sel,
380 0xff00 - sizeof(*stack16Top) );
381 stack16Top = (STACK16FRAME *)PTR_SEG_TO_LIN(thdb->cur_stack);
382 stack16Top->frame32 = 0;
383 stack16Top->ebp = 0;
384 stack16Top->ds = stack16Top->es = pModule->self_loading_sel;
385 stack16Top->entry_point = 0;
386 stack16Top->entry_ip = 0;
387 stack16Top->entry_cs = 0;
388 stack16Top->bp = 0;
389 stack16Top->ip = 0;
390 stack16Top->cs = 0;
392 hf = FILE_DupUnixHandle( MODULE_OpenFile( pModule->self ) );
393 Callbacks->CallBootAppProc(selfloadheader->BootApp, pModule->self, hf);
394 _lclose32(hf);
395 /* some BootApp procs overwrite the selector of dgroup */
396 pSegTable[pModule->dgroup - 1].selector = saved_dgroup;
397 thdb->cur_stack = oldstack;
398 for (i = 2; i <= pModule->seg_count; i++)
399 if (!NE_LoadSegment( pModule, i )) return FALSE;
401 else
403 for (i = 1; i <= pModule->seg_count; i++)
404 if (!NE_LoadSegment( pModule, i )) return FALSE;
406 return TRUE;
410 /***********************************************************************
411 * NE_LoadDLLs
413 BOOL32 NE_LoadDLLs( NE_MODULE *pModule )
415 int i;
416 WORD *pModRef = (WORD *)((char *)pModule + pModule->modref_table);
417 WORD *pDLLs = (WORD *)GlobalLock16( pModule->dlls_to_init );
419 for (i = 0; i < pModule->modref_count; i++, pModRef++)
421 char buffer[256];
422 BYTE *pstr = (BYTE *)pModule + pModule->import_table + *pModRef;
423 memcpy( buffer, pstr + 1, *pstr );
424 strcpy( buffer + *pstr, ".dll" );
425 TRACE(module, "Loading '%s'\n", buffer );
426 if (!(*pModRef = MODULE_FindModule( buffer )))
428 /* If the DLL is not loaded yet, load it and store */
429 /* its handle in the list of DLLs to initialize. */
430 HMODULE16 hDLL;
432 if ((hDLL = MODULE_Load( buffer, (LPVOID)-1, NE_FFLAGS_IMPLICIT )) == 2)
434 /* file not found */
435 char *p;
437 /* Try with prepending the path of the current module */
438 GetModuleFileName16( pModule->self, buffer, sizeof(buffer) );
439 if (!(p = strrchr( buffer, '\\' ))) p = buffer;
440 memcpy( p + 1, pstr + 1, *pstr );
441 strcpy( p + 1 + *pstr, ".dll" );
442 hDLL = MODULE_Load( buffer, (LPVOID)-1, NE_FFLAGS_IMPLICIT );
444 if (hDLL < 32)
446 /* FIXME: cleanup what was done */
448 fprintf( stderr, "Could not load '%s' required by '%.*s', error = %d\n",
449 buffer, *((BYTE*)pModule + pModule->name_table),
450 (char *)pModule + pModule->name_table + 1, hDLL );
451 return FALSE;
453 *pModRef = MODULE_HANDLEtoHMODULE16( hDLL );
454 *pDLLs++ = *pModRef;
456 else /* Increment the reference count of the DLL */
458 NE_MODULE *pOldDLL = MODULE_GetPtr( *pModRef );
459 if (pOldDLL) pOldDLL->count++;
462 return TRUE;
466 /***********************************************************************
467 * NE_FixupPrologs
469 * Fixup the exported functions prologs.
471 void NE_FixupPrologs( NE_MODULE *pModule )
473 SEGTABLEENTRY *pSegTable;
474 WORD dgroup = 0;
475 WORD sel;
476 BYTE *p, *fixup_ptr, count;
477 dbg_decl_str(module, 512);
479 pSegTable = NE_SEG_TABLE(pModule);
480 if (pModule->flags & NE_FFLAGS_SINGLEDATA)
481 dgroup = pSegTable[pModule->dgroup-1].selector;
483 TRACE(module, "(%04x)\n", pModule->self );
484 p = (BYTE *)pModule + pModule->entry_table;
485 while (*p)
487 if (p[1] == 0) /* Unused entry */
489 p += 2; /* Skip it */
490 continue;
492 if (p[1] == 0xfe) /* Constant entry */
494 p += 2 + *p * 3; /* Skip it */
495 continue;
498 /* Now fixup the entries of this bundle */
499 count = *p;
500 sel = p[1];
501 p += 2;
502 while (count-- > 0)
504 dbg_reset_str(module);
505 dsprintf(module,"Flags: %04x, sel %02x ", *p, sel);
506 /* According to the output generated by TDUMP, the flags mean:
507 * 0x0001 function is exported
508 * 0x0002 Single data (seems to occur only in DLLs)
510 if (sel == 0xff) { /* moveable */
511 dsprintf(module, "(%02x) o %04x", p[3], *(WORD *)(p+4) );
512 fixup_ptr = (char *)GET_SEL_BASE(pSegTable[p[3]-1].selector) + *(WORD *)(p + 4);
513 } else { /* fixed */
514 dsprintf(module, "offset %04x", *(WORD *)(p+1) );
515 fixup_ptr = (char *)GET_SEL_BASE(pSegTable[sel-1].selector) +
516 *(WORD *)(p + 1);
518 TRACE(module, "%s Signature: %02x %02x %02x,ff %x\n",
519 dbg_str(module), fixup_ptr[0], fixup_ptr[1],
520 fixup_ptr[2], pModule->flags );
521 if (*p & 0x0001)
523 /* Verify the signature */
524 if (((fixup_ptr[0] == 0x1e && fixup_ptr[1] == 0x58)
525 || (fixup_ptr[0] == 0x8c && fixup_ptr[1] == 0xd8))
526 && fixup_ptr[2] == 0x90)
528 if (*p & 0x0002)
530 if (pModule->flags & NE_FFLAGS_MULTIPLEDATA)
532 /* can this happen? */
533 fprintf( stderr, "FixupPrologs got confused\n" );
535 else if (pModule->flags & NE_FFLAGS_SINGLEDATA)
537 *fixup_ptr = 0xb8; /* MOV AX, */
538 *(WORD *)(fixup_ptr+1) = dgroup;
541 else
543 if (pModule->flags & NE_FFLAGS_MULTIPLEDATA) {
544 fixup_ptr[0] = 0x90; /* non-library: NOPs */
545 fixup_ptr[1] = 0x90;
546 fixup_ptr[2] = 0x90;
549 } else {
550 WARN(fixup, "Unknown signature\n" );
553 else
554 TRACE(module,"\n");
555 p += (sel == 0xff) ? 6 : 3;
561 /***********************************************************************
562 * NE_InitDLL
564 * Call the DLL initialization code
566 static BOOL32 NE_InitDLL( TDB* pTask, HMODULE16 hModule )
568 NE_MODULE *pModule;
569 SEGTABLEENTRY *pSegTable;
570 CONTEXT context;
572 /* Registers at initialization must be:
573 * cx heap size
574 * di library instance
575 * ds data segment if any
576 * es:si command line (always 0)
579 if (!(pModule = MODULE_GetPtr( hModule ))) return FALSE;
580 pSegTable = NE_SEG_TABLE( pModule );
582 if (!(pModule->flags & NE_FFLAGS_LIBMODULE) ||
583 (pModule->flags & NE_FFLAGS_WIN32)) return TRUE; /*not a library*/
585 /* Call USER signal handler. This is necessary to install a
586 * proper loader for HICON and HCURSOR resources that this DLL
587 * may contain. InitApp() does this for task modules. */
589 if (pTask && pTask->userhandler)
591 pTask->userhandler( hModule, USIG_DLL_LOAD, 0, pTask->hInstance,
592 pTask->hQueue );
595 if (!pModule->cs) return TRUE; /* no initialization code */
597 memset( &context, 0, sizeof(context) );
599 if (!(pModule->flags & NE_FFLAGS_SINGLEDATA))
601 if (pModule->flags & NE_FFLAGS_MULTIPLEDATA || pModule->dgroup)
603 /* Not SINGLEDATA */
604 fprintf(stderr, "Library is not marked SINGLEDATA\n");
605 exit(1);
607 else /* DATA NONE DLL */
609 DS_reg(&context) = 0;
610 ECX_reg(&context) = 0;
613 else /* DATA SINGLE DLL */
615 if (pModule->dgroup) {
616 DS_reg(&context) = pSegTable[pModule->dgroup-1].selector;
617 ECX_reg(&context) = pModule->heap_size;
619 else /* hmm, DLL has no dgroup,
620 but why has it NE_FFLAGS_SINGLEDATA set ?
621 Buggy DLL compiler ? */
623 DS_reg(&context) = 0;
624 ECX_reg(&context) = 0;
628 CS_reg(&context) = pSegTable[pModule->cs-1].selector;
629 EIP_reg(&context) = pModule->ip;
630 EBP_reg(&context) = OFFSETOF(THREAD_Current()->cur_stack)
631 + (WORD)&((STACK16FRAME*)0)->bp;
632 EDI_reg(&context) = DS_reg(&context) ? DS_reg(&context) : hModule;
635 pModule->cs = 0; /* Don't initialize it twice */
636 TRACE(dll, "Calling LibMain, cs:ip=%04lx:%04x ds=%04lx di=%04x cx=%04x\n",
637 CS_reg(&context), IP_reg(&context), DS_reg(&context),
638 DI_reg(&context), CX_reg(&context) );
639 Callbacks->CallRegisterShortProc( &context, 0 );
640 return TRUE;
644 /***********************************************************************
645 * NE_InitializeDLLs
647 * Recursively initialize all DLLs (according to the order in which
648 * they where loaded).
650 void NE_InitializeDLLs( HMODULE16 hModule )
652 TDB* pTask = (TDB*)GlobalLock16(GetCurrentTask());
653 NE_MODULE *pModule;
654 HMODULE16 *pDLL;
656 if (!(pModule = MODULE_GetPtr( hModule ))) return;
657 if (pModule->flags & NE_FFLAGS_WIN32) return;
659 if (pModule->dlls_to_init)
661 HGLOBAL16 to_init = pModule->dlls_to_init;
662 pModule->dlls_to_init = 0;
663 for (pDLL = (HMODULE16 *)GlobalLock16( to_init ); *pDLL; pDLL++)
665 NE_InitializeDLLs( *pDLL );
667 GlobalFree16( to_init );
669 NE_InitDLL( pTask, hModule );
673 /***********************************************************************
674 * PatchCodeHandle
676 * Needed for self-loading modules.
679 /* It does nothing */
680 void WINAPI PatchCodeHandle(HANDLE16 hSel)
682 fprintf(stderr,"PatchCodeHandle(%04x),stub!\n",hSel);