4 * Copyright 1993 Robert J. Amstadt
5 * Copyright 1995 Alexandre Julliard
11 #include <sys/types.h>
19 #include "wine/winbase16.h"
23 #include "selectors.h"
27 #include "stackframe.h"
28 #include "builtin16.h"
29 #include "debugtools.h"
33 DECLARE_DEBUG_CHANNEL(dll)
34 DECLARE_DEBUG_CHANNEL(fixup)
35 DECLARE_DEBUG_CHANNEL(module)
36 DECLARE_DEBUG_CHANNEL(segment)
38 #define SEL(x) ((x)|1)
40 static void NE_FixupSegmentPrologs(NE_MODULE *pModule, WORD segnum);
42 /***********************************************************************
45 static const char *NE_GetRelocAddrName( BYTE addr_type, int additive )
47 switch(addr_type & 0x7f)
49 case NE_RADDR_LOWBYTE: return additive ? "BYTE add" : "BYTE";
50 case NE_RADDR_OFFSET16: return additive ? "OFFSET16 add" : "OFFSET16";
51 case NE_RADDR_POINTER32: return additive ? "POINTER32 add" : "POINTER32";
52 case NE_RADDR_SELECTOR: return additive ? "SELECTOR add" : "SELECTOR";
53 case NE_RADDR_POINTER48: return additive ? "POINTER48 add" : "POINTER48";
54 case NE_RADDR_OFFSET32: return additive ? "OFFSET32 add" : "OFFSET32";
60 /***********************************************************************
63 BOOL NE_LoadSegment( NE_MODULE *pModule, WORD segnum )
65 SEGTABLEENTRY *pSegTable, *pSeg;
67 WORD count, i, offset, next_offset;
69 FARPROC16 address = 0;
72 struct relocation_entry_s *rep, *reloc_entries;
78 int ordinal, additive;
81 pSegTable = NE_SEG_TABLE( pModule );
82 pSeg = pSegTable + segnum - 1;
84 if (pSeg->flags & NE_SEGFLAGS_LOADED)
86 /* self-loader ? -> already loaded it */
87 if (pModule->flags & NE_FFLAGS_SELFLOAD)
90 /* leave, except for DGROUP, as this may be the second instance */
91 if (segnum != pModule->dgroup)
95 if (!pSeg->filepos) return TRUE; /* No file image, just return */
97 pModuleTable = NE_MODULE_TABLE( pModule );
99 hf = NE_OpenFile( pModule );
100 TRACE_(module)("Loading segment %d, hSeg=%04x, flags=%04x\n",
101 segnum, pSeg->hSeg, pSeg->flags );
102 SetFilePointer( hf, pSeg->filepos << pModule->alignment, NULL, SEEK_SET );
103 if (pSeg->size) size = pSeg->size;
104 else size = pSeg->minsize ? pSeg->minsize : 0x10000;
105 mem = GlobalLock16(pSeg->hSeg);
106 if (pModule->flags & NE_FFLAGS_SELFLOAD && segnum > 1)
108 /* Implement self-loading segments */
109 SELFLOADHEADER *selfloadheader;
114 selfloadheader = (SELFLOADHEADER *)
115 PTR_SEG_OFF_TO_LIN(SEL(pSegTable->hSeg),0);
116 oldstack = NtCurrentTeb()->cur_stack;
117 NtCurrentTeb()->cur_stack = PTR_SEG_OFF_TO_SEGPTR(pModule->self_loading_sel,
118 0xff00 - sizeof(STACK16FRAME));
120 TRACE_(dll)("CallLoadAppSegProc(hmodule=0x%04x,hf=0x%04x,segnum=%d\n",
121 pModule->self,hf,segnum );
122 DuplicateHandle( GetCurrentProcess(), hf, GetCurrentProcess(), &hFile32,
123 0, FALSE, DUPLICATE_SAME_ACCESS );
124 hFile16 = FILE_AllocDosHandle( hFile32 );
125 pSeg->hSeg = Callbacks->CallLoadAppSegProc( selfloadheader->LoadAppSeg,
126 pModule->self, hFile16,
128 TRACE_(dll)("Ret CallLoadAppSegProc: hSeg = 0x%04x\n", pSeg->hSeg);
129 _lclose16( hFile16 );
130 NtCurrentTeb()->cur_stack = oldstack;
132 else if (!(pSeg->flags & NE_SEGFLAGS_ITERATED))
133 ReadFile(hf, mem, size, &res, NULL);
136 The following bit of code for "iterated segments" was written without
137 any documentation on the format of these segments. It seems to work,
138 but may be missing something. If you have any doc please either send
139 it to me or fix the code yourself. gfm@werple.mira.net.au
141 char* buff = xmalloc(size);
143 ReadFile(hf, buff, size, &res, NULL);
144 while(curr < buff + size) {
145 unsigned int rept = *((short*) curr)++;
146 unsigned int len = *((short*) curr)++;
147 for(; rept > 0; rept--) {
150 for(byte = 0; byte < len; byte++)
158 pSeg->flags |= NE_SEGFLAGS_LOADED;
160 /* Perform exported function prolog fixups */
161 NE_FixupSegmentPrologs( pModule, segnum );
163 if (!(pSeg->flags & NE_SEGFLAGS_RELOC_DATA))
164 return TRUE; /* No relocation data, we are done */
166 ReadFile(hf, &count, sizeof(count), &res, NULL);
167 if (!count) return TRUE;
169 TRACE_(fixup)("Fixups for %.*s, segment %d, hSeg %04x\n",
170 *((BYTE *)pModule + pModule->name_table),
171 (char *)pModule + pModule->name_table + 1,
172 segnum, pSeg->hSeg );
173 TRACE_(segment)("Fixups for %.*s, segment %d, hSeg %04x\n",
174 *((BYTE *)pModule + pModule->name_table),
175 (char *)pModule + pModule->name_table + 1,
176 segnum, pSeg->hSeg );
178 reloc_entries = (struct relocation_entry_s *)xmalloc(count * sizeof(struct relocation_entry_s));
179 if (!ReadFile( hf, reloc_entries, count * sizeof(struct relocation_entry_s), &res, NULL) ||
180 (res != count * sizeof(struct relocation_entry_s)))
182 WARN_(fixup)("Unable to read relocation information\n" );
187 * Go through the relocation table one entry at a time.
190 for (i = 0; i < count; i++, rep++)
193 * Get the target address corresponding to this entry.
196 /* If additive, there is no target chain list. Instead, add source
198 additive = rep->relocation_type & NE_RELFLAG_ADDITIVE;
199 rep->relocation_type &= 0x3;
201 switch (rep->relocation_type)
203 case NE_RELTYPE_ORDINAL:
204 module = pModuleTable[rep->target1-1];
205 ordinal = rep->target2;
206 address = NE_GetEntryPoint( module, ordinal );
209 NE_MODULE *pTarget = NE_GetPtr( module );
211 WARN_(module)("Module not found: %04x, reference %d of module %*.*s\n",
212 module, rep->target1,
213 *((BYTE *)pModule + pModule->name_table),
214 *((BYTE *)pModule + pModule->name_table),
215 (char *)pModule + pModule->name_table + 1 );
218 ERR_(fixup)("No implementation for %.*s.%d, setting to 0xdeadbeef\n",
219 *((BYTE *)pTarget + pTarget->name_table),
220 (char *)pTarget + pTarget->name_table + 1,
222 address = (FARPROC16)0xdeadbeef;
227 NE_MODULE *pTarget = NE_GetPtr( module );
228 TRACE_(fixup)("%d: %.*s.%d=%04x:%04x %s\n", i + 1,
229 *((BYTE *)pTarget + pTarget->name_table),
230 (char *)pTarget + pTarget->name_table + 1,
231 ordinal, HIWORD(address), LOWORD(address),
232 NE_GetRelocAddrName( rep->address_type, additive ) );
236 case NE_RELTYPE_NAME:
237 module = pModuleTable[rep->target1-1];
238 func_name = (char *)pModule + pModule->import_table + rep->target2;
239 memcpy( buffer, func_name+1, *func_name );
240 buffer[*func_name] = '\0';
242 ordinal = NE_GetOrdinal( module, func_name );
243 address = NE_GetEntryPoint( module, ordinal );
245 if (ERR_ON(fixup) && !address)
247 NE_MODULE *pTarget = NE_GetPtr( module );
248 ERR_(fixup)("No implementation for %.*s.%s, setting to 0xdeadbeef\n",
249 *((BYTE *)pTarget + pTarget->name_table),
250 (char *)pTarget + pTarget->name_table + 1, func_name );
252 if (!address) address = (FARPROC16) 0xdeadbeef;
255 NE_MODULE *pTarget = NE_GetPtr( module );
256 TRACE_(fixup)("%d: %.*s.%s=%04x:%04x %s\n", i + 1,
257 *((BYTE *)pTarget + pTarget->name_table),
258 (char *)pTarget + pTarget->name_table + 1,
259 func_name, HIWORD(address), LOWORD(address),
260 NE_GetRelocAddrName( rep->address_type, additive ) );
264 case NE_RELTYPE_INTERNAL:
265 if ((rep->target1 & 0xff) == 0xff)
267 address = NE_GetEntryPoint( pModule->self, rep->target2 );
271 address = (FARPROC16)PTR_SEG_OFF_TO_SEGPTR( SEL(pSegTable[rep->target1-1].hSeg), rep->target2 );
274 TRACE_(fixup)("%d: %04x:%04x %s\n",
275 i + 1, HIWORD(address), LOWORD(address),
276 NE_GetRelocAddrName( rep->address_type, additive ) );
279 case NE_RELTYPE_OSFIXUP:
280 /* Relocation type 7:
282 * These appear to be used as fixups for the Windows
283 * floating point emulator. Let's just ignore them and
284 * try to use the hardware floating point. Linux should
285 * successfully emulate the coprocessor if it doesn't
288 TRACE_(fixup)("%d: TYPE %d, OFFSET %04x, TARGET %04x %04x %s\n",
289 i + 1, rep->relocation_type, rep->offset,
290 rep->target1, rep->target2,
291 NE_GetRelocAddrName( rep->address_type, additive ) );
295 offset = rep->offset;
297 /* Apparently, high bit of address_type is sometimes set; */
298 /* we ignore it for now */
299 if (rep->address_type > NE_RADDR_OFFSET32)
302 GetModuleName16( pModule->self, module, sizeof(module) );
303 ERR_(fixup)("WARNING: module %s: unknown reloc addr type = 0x%02x. Please report.\n",
304 module, rep->address_type );
309 sp = PTR_SEG_OFF_TO_LIN( SEL(pSeg->hSeg), offset );
310 TRACE_(fixup)(" %04x:%04x\n", offset, *sp );
311 switch (rep->address_type & 0x7f)
313 case NE_RADDR_LOWBYTE:
314 *(BYTE *)sp += LOBYTE((int)address);
316 case NE_RADDR_OFFSET16:
317 *sp += LOWORD(address);
319 case NE_RADDR_POINTER32:
320 *sp += LOWORD(address);
321 *(sp+1) = HIWORD(address);
323 case NE_RADDR_SELECTOR:
324 /* Borland creates additive records with offset zero. Strange, but OK */
326 ERR_(fixup)("Additive selector to %04x.Please report\n",*sp);
328 *sp = HIWORD(address);
334 else /* non-additive fixup */
338 sp = PTR_SEG_OFF_TO_LIN( SEL(pSeg->hSeg), offset );
340 TRACE_(fixup)(" %04x:%04x\n", offset, *sp );
341 switch (rep->address_type & 0x7f)
343 case NE_RADDR_LOWBYTE:
344 *(BYTE *)sp = LOBYTE((int)address);
346 case NE_RADDR_OFFSET16:
347 *sp = LOWORD(address);
349 case NE_RADDR_POINTER32:
350 *(FARPROC16 *)sp = address;
352 case NE_RADDR_SELECTOR:
353 *sp = SELECTOROF(address);
358 if (next_offset == offset) break; /* avoid infinite loop */
359 if (next_offset >= GlobalSize16(pSeg->hSeg)) break;
360 offset = next_offset;
361 } while (offset != 0xffff);
369 WARN_(fixup)("WARNING: %d: unknown ADDR TYPE %d, "
370 "TYPE %d, OFFSET %04x, TARGET %04x %04x\n",
371 i + 1, rep->address_type, rep->relocation_type,
372 rep->offset, rep->target1, rep->target2);
378 /***********************************************************************
381 BOOL NE_LoadAllSegments( NE_MODULE *pModule )
384 SEGTABLEENTRY * pSegTable = (SEGTABLEENTRY *) NE_SEG_TABLE(pModule);
386 if (pModule->flags & NE_FFLAGS_SELFLOAD)
390 /* Handle self-loading modules */
391 SELFLOADHEADER *selfloadheader;
392 HMODULE16 hselfload = GetModuleHandle16("WPROCS");
395 TRACE_(module)("%.*s is a self-loading module!\n",
396 *((BYTE*)pModule + pModule->name_table),
397 (char *)pModule + pModule->name_table + 1);
398 if (!NE_LoadSegment( pModule, 1 )) return FALSE;
399 selfloadheader = (SELFLOADHEADER *)
400 PTR_SEG_OFF_TO_LIN(SEL(pSegTable->hSeg), 0);
401 selfloadheader->EntryAddrProc = NE_GetEntryPoint(hselfload,27);
402 selfloadheader->MyAlloc = NE_GetEntryPoint(hselfload,28);
403 selfloadheader->SetOwner = NE_GetEntryPoint(GetModuleHandle16("KERNEL"),403);
404 pModule->self_loading_sel = SEL(GLOBAL_Alloc(GMEM_ZEROINIT, 0xFF00, pModule->self, FALSE, FALSE, FALSE));
405 oldstack = NtCurrentTeb()->cur_stack;
406 NtCurrentTeb()->cur_stack = PTR_SEG_OFF_TO_SEGPTR(pModule->self_loading_sel,
407 0xff00 - sizeof(STACK16FRAME) );
409 DuplicateHandle( GetCurrentProcess(), NE_OpenFile(pModule),
410 GetCurrentProcess(), &hf, 0, FALSE, DUPLICATE_SAME_ACCESS );
411 hFile16 = FILE_AllocDosHandle( hf );
412 TRACE_(dll)("CallBootAppProc(hModule=0x%04x,hf=0x%04x)\n",
413 pModule->self,hFile16);
414 Callbacks->CallBootAppProc(selfloadheader->BootApp, pModule->self,hFile16);
415 TRACE_(dll)("Return from CallBootAppProc\n");
417 NtCurrentTeb()->cur_stack = oldstack;
419 for (i = 2; i <= pModule->seg_count; i++)
420 if (!NE_LoadSegment( pModule, i )) return FALSE;
424 for (i = 1; i <= pModule->seg_count; i++)
425 if (!NE_LoadSegment( pModule, i )) return FALSE;
431 /***********************************************************************
432 * NE_FixupSegmentPrologs
434 * Fixup exported functions prologs of one segment
436 static void NE_FixupSegmentPrologs(NE_MODULE *pModule, WORD segnum)
438 SEGTABLEENTRY *pSegTable = NE_SEG_TABLE( pModule );
441 WORD dgroup, num_entries, sel = SEL(pSegTable[segnum-1].hSeg);
444 TRACE_(module)("(%d);\n", segnum);
446 if (pSegTable[segnum-1].flags & NE_SEGFLAGS_DATA)
448 pSegTable[segnum-1].flags |= NE_SEGFLAGS_LOADED;
452 if (!pModule->dgroup) return;
454 if (!(dgroup = SEL(pSegTable[pModule->dgroup-1].hSeg))) return;
456 pSeg = PTR_SEG_OFF_TO_LIN(sel, 0);
458 bundle = (ET_BUNDLE *)((BYTE *)pModule+pModule->entry_table);
461 TRACE_(module)("num_entries: %d, bundle: %p, next: %04x, pSeg: %p\n", bundle->last - bundle->first, bundle, bundle->next, pSeg);
462 if (!(num_entries = bundle->last - bundle->first))
464 entry = (ET_ENTRY *)((BYTE *)bundle+6);
465 while (num_entries--)
467 /*TRACE(module, "entry: %p, entry->segnum: %d, entry->offs: %04x\n", entry, entry->segnum, entry->offs);*/
468 if (entry->segnum == segnum)
470 pFunc = ((BYTE *)pSeg+entry->offs);
471 TRACE_(module)("pFunc: %p, *(DWORD *)pFunc: %08lx, num_entries: %d\n", pFunc, *(DWORD *)pFunc, num_entries);
472 if (*(pFunc+2) == 0x90)
474 if (*(WORD *)pFunc == 0x581e) /* push ds, pop ax */
476 TRACE_(module)("patch %04x:%04x -> mov ax, ds\n", sel, entry->offs);
477 *(WORD *)pFunc = 0xd88c; /* mov ax, ds */
480 if (*(WORD *)pFunc == 0xd88c)
482 if ((entry->flags & 2)) /* public data ? */
484 TRACE_(module)("patch %04x:%04x -> mov ax, dgroup [%04x]\n", sel, entry->offs, dgroup);
485 *pFunc = 0xb8; /* mov ax, */
486 *(WORD *)(pFunc+1) = dgroup;
489 if ((pModule->flags & NE_FFLAGS_MULTIPLEDATA)
490 && (entry->flags & 1)) /* exported ? */
492 TRACE_(module)("patch %04x:%04x -> nop, nop\n", sel, entry->offs);
493 *(WORD *)pFunc = 0x9090; /* nop, nop */
500 } while ( (bundle->next)
501 && (bundle = ((ET_BUNDLE *)((BYTE *)pModule + bundle->next))) );
505 /***********************************************************************
508 * Needed for self-loading modules.
510 DWORD WINAPI PatchCodeHandle16(HANDLE16 hSeg)
513 WORD sel = SEL(hSeg);
514 NE_MODULE *pModule = NE_GetPtr(FarGetOwner16(sel));
515 SEGTABLEENTRY *pSegTable = NE_SEG_TABLE(pModule);
517 TRACE_(module)("(%04x);\n", hSeg);
519 /* find the segment number of the module that belongs to hSeg */
520 for (segnum = 1; segnum <= pModule->seg_count; segnum++)
522 if (SEL(pSegTable[segnum-1].hSeg) == sel)
524 NE_FixupSegmentPrologs(pModule, segnum);
529 return MAKELONG(hSeg, sel);
533 /***********************************************************************
534 * NE_GetDLLInitParams
536 static VOID NE_GetDLLInitParams( NE_MODULE *pModule,
537 WORD *hInst, WORD *ds, WORD *heap )
539 SEGTABLEENTRY *pSegTable = NE_SEG_TABLE( pModule );
541 if (!(pModule->flags & NE_FFLAGS_SINGLEDATA))
543 if (pModule->flags & NE_FFLAGS_MULTIPLEDATA || pModule->dgroup)
546 ERR_(dll)("Library is not marked SINGLEDATA\n");
549 else /* DATA NONE DLL */
555 else /* DATA SINGLE DLL */
557 if (pModule->dgroup) {
558 *ds = SEL(pSegTable[pModule->dgroup-1].hSeg);
559 *heap = pModule->heap_size;
561 else /* hmm, DLL has no dgroup,
562 but why has it NE_FFLAGS_SINGLEDATA set ?
563 Buggy DLL compiler ? */
570 *hInst = *ds ? *ds : pModule->self;
574 /***********************************************************************
577 * Call the DLL initialization code
579 static BOOL NE_InitDLL( TDB* pTask, NE_MODULE *pModule )
581 SEGTABLEENTRY *pSegTable;
582 WORD hInst, ds, heap;
585 pSegTable = NE_SEG_TABLE( pModule );
587 if (!(pModule->flags & NE_FFLAGS_LIBMODULE) ||
588 (pModule->flags & NE_FFLAGS_WIN32)) return TRUE; /*not a library*/
590 /* Call USER signal handler for Win3.1 compatibility. */
591 TASK_CallTaskSignalProc( USIG16_DLL_LOAD, pModule->self );
593 if (!pModule->cs) return TRUE; /* no initialization code */
596 /* Registers at initialization must be:
598 * di library instance
599 * ds data segment if any
600 * es:si command line (always 0)
603 memset( &context, 0, sizeof(context) );
605 NE_GetDLLInitParams( pModule, &hInst, &ds, &heap );
607 ECX_reg(&context) = heap;
608 EDI_reg(&context) = hInst;
609 DS_reg(&context) = ds;
610 ES_reg(&context) = ds; /* who knows ... */
612 CS_reg(&context) = SEL(pSegTable[pModule->cs-1].hSeg);
613 EIP_reg(&context) = pModule->ip;
614 EBP_reg(&context) = OFFSETOF(NtCurrentTeb()->cur_stack) + (WORD)&((STACK16FRAME*)0)->bp;
617 pModule->cs = 0; /* Don't initialize it twice */
618 TRACE_(dll)("Calling LibMain, cs:ip=%04lx:%04lx ds=%04lx di=%04x cx=%04x\n",
619 CS_reg(&context), EIP_reg(&context), DS_reg(&context),
620 DI_reg(&context), CX_reg(&context) );
621 Callbacks->CallRegisterShortProc( &context, 0 );
625 /***********************************************************************
628 * Recursively initialize all DLLs (according to the order in which
629 * they where loaded).
631 void NE_InitializeDLLs( HMODULE16 hModule )
633 TDB* pTask = (TDB*)GlobalLock16(GetCurrentTask());
637 if (!(pModule = NE_GetPtr( hModule ))) return;
638 assert( !(pModule->flags & NE_FFLAGS_WIN32) );
640 if (pModule->dlls_to_init)
642 HGLOBAL16 to_init = pModule->dlls_to_init;
643 pModule->dlls_to_init = 0;
644 for (pDLL = (HMODULE16 *)GlobalLock16( to_init ); *pDLL; pDLL++)
646 NE_InitializeDLLs( *pDLL );
648 GlobalFree16( to_init );
650 NE_InitDLL( pTask, pModule );
654 /***********************************************************************
655 * NE_CallDllEntryPoint
657 * Call the DllEntryPoint of DLLs with subsystem >= 4.0
659 typedef DWORD WINAPI (*WinNEEntryProc)(DWORD,WORD,WORD,WORD,DWORD,WORD);
661 static void NE_CallDllEntryPoint( NE_MODULE *pModule, DWORD dwReason )
663 WORD hInst, ds, heap;
664 FARPROC16 entryPoint;
667 if (!(pModule->flags & NE_FFLAGS_LIBMODULE)) return;
668 if (!(pModule->flags & NE_FFLAGS_BUILTIN) && pModule->expected_version < 0x0400) return;
669 if (!(ordinal = NE_GetOrdinal( pModule->self, "DllEntryPoint" ))) return;
670 if (!(entryPoint = NE_GetEntryPoint( pModule->self, ordinal ))) return;
672 NE_GetDLLInitParams( pModule, &hInst, &ds, &heap );
674 TRACE_(dll)( "Calling %s DllEntryPoint, cs:ip=%04x:%04x\n",
675 NE_MODULE_NAME( pModule ),
676 SELECTOROF(entryPoint), OFFSETOF(entryPoint) );
678 if ( pModule->flags & NE_FFLAGS_BUILTIN )
680 WinNEEntryProc entryProc = (WinNEEntryProc)
681 ((ENTRYPOINT16 *)PTR_SEG_TO_LIN( entryPoint ))->target;
683 entryProc( dwReason, hInst, ds, heap, 0, 0 );
687 LPBYTE stack = (LPBYTE)CURRENT_STACK16;
690 memset( &context, 0, sizeof(context) );
691 DS_reg(&context) = ds;
692 ES_reg(&context) = ds; /* who knows ... */
694 CS_reg(&context) = HIWORD(entryPoint);
695 EIP_reg(&context) = LOWORD(entryPoint);
696 EBP_reg(&context) = OFFSETOF( NtCurrentTeb()->cur_stack )
697 + (WORD)&((STACK16FRAME*)0)->bp;
699 *(DWORD *)(stack - 4) = dwReason; /* dwReason */
700 *(WORD *) (stack - 6) = hInst; /* hInst */
701 *(WORD *) (stack - 8) = ds; /* wDS */
702 *(WORD *) (stack - 10) = heap; /* wHeapSize */
703 *(DWORD *)(stack - 14) = 0; /* dwReserved1 */
704 *(WORD *) (stack - 16) = 0; /* wReserved2 */
706 Callbacks->CallRegisterShortProc( &context, 16 );
710 /***********************************************************************
711 * NE_DllProcessAttach
713 * Call the DllEntryPoint of all modules this one (recursively)
714 * depends on, according to the order in which they were loaded.
716 * Note that --as opposed to the PE module case-- there is no notion
717 * of 'module loaded into a process' for NE modules, and hence we
718 * have no place to store the fact that the DllEntryPoint of a
719 * given module was already called on behalf of this process (e.g.
720 * due to some earlier LoadLibrary16 call).
722 * Thus, we just call the DllEntryPoint twice in that case. Win9x
723 * appears to behave this way as well ...
725 * This routine must only be called with the Win16Lock held.
727 * FIXME: We should actually abort loading in case the DllEntryPoint
731 void NE_DllProcessAttach( HMODULE16 hModule )
737 if (!(pModule = NE_GetPtr( hModule ))) return;
738 assert( !(pModule->flags & NE_FFLAGS_WIN32) );
740 /* Check for recursive call */
741 if ( pModule->misc_flags & 0x80 ) return;
743 TRACE_(dll)("(%s) - START\n", NE_MODULE_NAME(pModule) );
745 /* Tag current module to prevent recursive loop */
746 pModule->misc_flags |= 0x80;
748 /* Recursively attach all DLLs this one depends on */
749 pModRef = NE_MODULE_TABLE( pModule );
750 for ( i = 0; i < pModule->modref_count; i++ )
752 NE_DllProcessAttach( (HMODULE16)pModRef[i] );
754 /* Call DLL entry point */
755 NE_CallDllEntryPoint( pModule, DLL_PROCESS_ATTACH );
757 /* Remove recursion flag */
758 pModule->misc_flags &= ~0x80;
760 TRACE_(dll)("(%s) - END\n", NE_MODULE_NAME(pModule) );
764 /***********************************************************************
767 * This function translates NE segment flags to GlobalAlloc flags
769 static WORD NE_Ne2MemFlags(WORD flags)
773 if (flags & NE_SEGFLAGS_DISCARDABLE)
774 memflags |= GMEM_DISCARDABLE;
775 if (flags & NE_SEGFLAGS_MOVEABLE ||
776 ( ! (flags & NE_SEGFLAGS_DATA) &&
777 ! (flags & NE_SEGFLAGS_LOADED) &&
778 ! (flags & NE_SEGFLAGS_ALLOCATED)
781 memflags |= GMEM_MOVEABLE;
782 memflags |= GMEM_ZEROINIT;
784 memflags = GMEM_ZEROINIT | GMEM_FIXED;
789 /***********************************************************************
790 * NE_AllocateSegment (WPROCS.26)
792 * MyAlloc() function for self-loading apps.
794 DWORD WINAPI NE_AllocateSegment( WORD wFlags, WORD wSize, WORD wElem )
796 WORD size = wSize << wElem;
799 if (wSize || (wFlags & NE_SEGFLAGS_MOVEABLE))
800 hMem = GlobalAlloc16( NE_Ne2MemFlags(wFlags), size);
802 if ( ((wFlags & 0x7) != 0x1) && /* DATA */
803 ((wFlags & 0x7) != 0x7) ) /* DATA|ALLOCATED|LOADED */
805 WORD hSel = SEL(hMem);
806 WORD access = SelectorAccessRights16(hSel,0,0);
808 access |= 2<<2; /* SEGMENT_CODE */
809 SelectorAccessRights16(hSel,1,access);
812 return MAKELONG( hMem, SEL(hMem) );
814 return MAKELONG( 0, hMem );
817 /***********************************************************************
820 HINSTANCE16 NE_GetInstance( NE_MODULE *pModule )
822 if ( !pModule->dgroup )
823 return pModule->self;
827 pSeg = NE_SEG_TABLE( pModule ) + pModule->dgroup - 1;
829 return SEL(pSeg->hSeg);
833 /***********************************************************************
836 BOOL NE_CreateSegment( NE_MODULE *pModule, int segnum )
838 SEGTABLEENTRY *pSeg = NE_SEG_TABLE( pModule ) + segnum - 1;
841 assert( !(pModule->flags & NE_FFLAGS_WIN32) );
843 if ( segnum < 1 || segnum > pModule->seg_count )
846 if ( (pModule->flags & NE_FFLAGS_SELFLOAD) && segnum != 1 )
847 return TRUE; /* selfloader allocates segment itself */
849 if ( (pSeg->flags & NE_SEGFLAGS_ALLOCATED) && segnum != pModule->dgroup )
850 return TRUE; /* all but DGROUP only allocated once */
852 minsize = pSeg->minsize ? pSeg->minsize : 0x10000;
853 if ( segnum == pModule->ss ) minsize += pModule->stack_size;
854 if ( segnum == pModule->dgroup ) minsize += pModule->heap_size;
856 pSeg->hSeg = GLOBAL_Alloc( NE_Ne2MemFlags(pSeg->flags),
857 minsize, pModule->self,
858 !(pSeg->flags & NE_SEGFLAGS_DATA),
859 (pSeg->flags & NE_SEGFLAGS_32BIT) != 0,
860 FALSE /*pSeg->flags & NE_SEGFLAGS_READONLY*/ );
861 if (!pSeg->hSeg) return FALSE;
863 pSeg->flags |= NE_SEGFLAGS_ALLOCATED;
867 /***********************************************************************
868 * NE_CreateAllSegments
870 BOOL NE_CreateAllSegments( NE_MODULE *pModule )
873 for ( i = 1; i <= pModule->seg_count; i++ )
874 if ( !NE_CreateSegment( pModule, i ) )
877 pModule->dgroup_entry = pModule->dgroup ? pModule->seg_table +
878 (pModule->dgroup - 1) * sizeof(SEGTABLEENTRY) : 0;
883 /**********************************************************************
884 * IsSharedSelector (KERNEL.345)
886 BOOL16 WINAPI IsSharedSelector16( HANDLE16 selector )
888 /* Check whether the selector belongs to a DLL */
889 NE_MODULE *pModule = NE_GetPtr( selector );
890 if (!pModule) return FALSE;
891 return (pModule->flags & NE_FFLAGS_LIBMODULE) != 0;