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) /* already loaded ? */
87 if (!pSeg->filepos) return TRUE; /* No file image, just return */
89 pModuleTable = NE_MODULE_TABLE( pModule );
91 hf = NE_OpenFile( pModule );
92 TRACE_(module)("Loading segment %d, hSeg=%04x, flags=%04x\n",
93 segnum, pSeg->hSeg, pSeg->flags );
94 SetFilePointer( hf, pSeg->filepos << pModule->alignment, NULL, SEEK_SET );
95 if (pSeg->size) size = pSeg->size;
96 else size = pSeg->minsize ? pSeg->minsize : 0x10000;
97 mem = GlobalLock16(pSeg->hSeg);
98 if (pModule->flags & NE_FFLAGS_SELFLOAD && segnum > 1)
100 /* Implement self-loading segments */
101 SELFLOADHEADER *selfloadheader;
106 selfloadheader = (SELFLOADHEADER *)
107 PTR_SEG_OFF_TO_LIN(SEL(pSegTable->hSeg),0);
108 oldstack = NtCurrentTeb()->cur_stack;
109 NtCurrentTeb()->cur_stack = PTR_SEG_OFF_TO_SEGPTR(pModule->self_loading_sel,
110 0xff00 - sizeof(STACK16FRAME));
112 TRACE_(dll)("CallLoadAppSegProc(hmodule=0x%04x,hf=0x%04x,segnum=%d\n",
113 pModule->self,hf,segnum );
114 DuplicateHandle( GetCurrentProcess(), hf, GetCurrentProcess(), &hFile32,
115 0, FALSE, DUPLICATE_SAME_ACCESS );
116 hFile16 = FILE_AllocDosHandle( hFile32 );
117 pSeg->hSeg = Callbacks->CallLoadAppSegProc( selfloadheader->LoadAppSeg,
118 pModule->self, hFile16,
120 TRACE_(dll)("Ret CallLoadAppSegProc: hSeg = 0x%04x\n", pSeg->hSeg);
121 _lclose16( hFile16 );
122 NtCurrentTeb()->cur_stack = oldstack;
124 else if (!(pSeg->flags & NE_SEGFLAGS_ITERATED))
125 ReadFile(hf, mem, size, &res, NULL);
128 The following bit of code for "iterated segments" was written without
129 any documentation on the format of these segments. It seems to work,
130 but may be missing something. If you have any doc please either send
131 it to me or fix the code yourself. gfm@werple.mira.net.au
133 char* buff = xmalloc(size);
135 ReadFile(hf, buff, size, &res, NULL);
136 while(curr < buff + size) {
137 unsigned int rept = *((short*) curr)++;
138 unsigned int len = *((short*) curr)++;
139 for(; rept > 0; rept--) {
142 for(byte = 0; byte < len; byte++)
150 pSeg->flags |= NE_SEGFLAGS_LOADED;
152 /* Perform exported function prolog fixups */
153 NE_FixupSegmentPrologs( pModule, segnum );
155 if (!(pSeg->flags & NE_SEGFLAGS_RELOC_DATA))
156 return TRUE; /* No relocation data, we are done */
158 ReadFile(hf, &count, sizeof(count), &res, NULL);
159 if (!count) return TRUE;
161 TRACE_(fixup)("Fixups for %.*s, segment %d, hSeg %04x\n",
162 *((BYTE *)pModule + pModule->name_table),
163 (char *)pModule + pModule->name_table + 1,
164 segnum, pSeg->hSeg );
165 TRACE_(segment)("Fixups for %.*s, segment %d, hSeg %04x\n",
166 *((BYTE *)pModule + pModule->name_table),
167 (char *)pModule + pModule->name_table + 1,
168 segnum, pSeg->hSeg );
170 reloc_entries = (struct relocation_entry_s *)xmalloc(count * sizeof(struct relocation_entry_s));
171 if (!ReadFile( hf, reloc_entries, count * sizeof(struct relocation_entry_s), &res, NULL) ||
172 (res != count * sizeof(struct relocation_entry_s)))
174 WARN_(fixup)("Unable to read relocation information\n" );
179 * Go through the relocation table one entry at a time.
182 for (i = 0; i < count; i++, rep++)
185 * Get the target address corresponding to this entry.
188 /* If additive, there is no target chain list. Instead, add source
190 additive = rep->relocation_type & NE_RELFLAG_ADDITIVE;
191 rep->relocation_type &= 0x3;
193 switch (rep->relocation_type)
195 case NE_RELTYPE_ORDINAL:
196 module = pModuleTable[rep->target1-1];
197 ordinal = rep->target2;
198 address = NE_GetEntryPoint( module, ordinal );
201 NE_MODULE *pTarget = NE_GetPtr( module );
203 WARN_(module)("Module not found: %04x, reference %d of module %*.*s\n",
204 module, rep->target1,
205 *((BYTE *)pModule + pModule->name_table),
206 *((BYTE *)pModule + pModule->name_table),
207 (char *)pModule + pModule->name_table + 1 );
210 ERR_(fixup)("No implementation for %.*s.%d, setting to 0xdeadbeef\n",
211 *((BYTE *)pTarget + pTarget->name_table),
212 (char *)pTarget + pTarget->name_table + 1,
214 address = (FARPROC16)0xdeadbeef;
219 NE_MODULE *pTarget = NE_GetPtr( module );
220 TRACE_(fixup)("%d: %.*s.%d=%04x:%04x %s\n", i + 1,
221 *((BYTE *)pTarget + pTarget->name_table),
222 (char *)pTarget + pTarget->name_table + 1,
223 ordinal, HIWORD(address), LOWORD(address),
224 NE_GetRelocAddrName( rep->address_type, additive ) );
228 case NE_RELTYPE_NAME:
229 module = pModuleTable[rep->target1-1];
230 func_name = (char *)pModule + pModule->import_table + rep->target2;
231 memcpy( buffer, func_name+1, *func_name );
232 buffer[*func_name] = '\0';
234 ordinal = NE_GetOrdinal( module, func_name );
235 address = NE_GetEntryPoint( module, ordinal );
237 if (ERR_ON(fixup) && !address)
239 NE_MODULE *pTarget = NE_GetPtr( module );
240 ERR_(fixup)("No implementation for %.*s.%s, setting to 0xdeadbeef\n",
241 *((BYTE *)pTarget + pTarget->name_table),
242 (char *)pTarget + pTarget->name_table + 1, func_name );
244 if (!address) address = (FARPROC16) 0xdeadbeef;
247 NE_MODULE *pTarget = NE_GetPtr( module );
248 TRACE_(fixup)("%d: %.*s.%s=%04x:%04x %s\n", i + 1,
249 *((BYTE *)pTarget + pTarget->name_table),
250 (char *)pTarget + pTarget->name_table + 1,
251 func_name, HIWORD(address), LOWORD(address),
252 NE_GetRelocAddrName( rep->address_type, additive ) );
256 case NE_RELTYPE_INTERNAL:
257 if ((rep->target1 & 0xff) == 0xff)
259 address = NE_GetEntryPoint( pModule->self, rep->target2 );
263 address = (FARPROC16)PTR_SEG_OFF_TO_SEGPTR( SEL(pSegTable[rep->target1-1].hSeg), rep->target2 );
266 TRACE_(fixup)("%d: %04x:%04x %s\n",
267 i + 1, HIWORD(address), LOWORD(address),
268 NE_GetRelocAddrName( rep->address_type, additive ) );
271 case NE_RELTYPE_OSFIXUP:
272 /* Relocation type 7:
274 * These appear to be used as fixups for the Windows
275 * floating point emulator. Let's just ignore them and
276 * try to use the hardware floating point. Linux should
277 * successfully emulate the coprocessor if it doesn't
280 TRACE_(fixup)("%d: TYPE %d, OFFSET %04x, TARGET %04x %04x %s\n",
281 i + 1, rep->relocation_type, rep->offset,
282 rep->target1, rep->target2,
283 NE_GetRelocAddrName( rep->address_type, additive ) );
287 offset = rep->offset;
289 /* Apparently, high bit of address_type is sometimes set; */
290 /* we ignore it for now */
291 if (rep->address_type > NE_RADDR_OFFSET32)
294 GetModuleName16( pModule->self, module, sizeof(module) );
295 ERR_(fixup)("WARNING: module %s: unknown reloc addr type = 0x%02x. Please report.\n",
296 module, rep->address_type );
301 sp = PTR_SEG_OFF_TO_LIN( SEL(pSeg->hSeg), offset );
302 TRACE_(fixup)(" %04x:%04x\n", offset, *sp );
303 switch (rep->address_type & 0x7f)
305 case NE_RADDR_LOWBYTE:
306 *(BYTE *)sp += LOBYTE((int)address);
308 case NE_RADDR_OFFSET16:
309 *sp += LOWORD(address);
311 case NE_RADDR_POINTER32:
312 *sp += LOWORD(address);
313 *(sp+1) = HIWORD(address);
315 case NE_RADDR_SELECTOR:
316 /* Borland creates additive records with offset zero. Strange, but OK */
318 ERR_(fixup)("Additive selector to %04x.Please report\n",*sp);
320 *sp = HIWORD(address);
326 else /* non-additive fixup */
330 sp = PTR_SEG_OFF_TO_LIN( SEL(pSeg->hSeg), offset );
332 TRACE_(fixup)(" %04x:%04x\n", offset, *sp );
333 switch (rep->address_type & 0x7f)
335 case NE_RADDR_LOWBYTE:
336 *(BYTE *)sp = LOBYTE((int)address);
338 case NE_RADDR_OFFSET16:
339 *sp = LOWORD(address);
341 case NE_RADDR_POINTER32:
342 *(FARPROC16 *)sp = address;
344 case NE_RADDR_SELECTOR:
345 *sp = SELECTOROF(address);
350 if (next_offset == offset) break; /* avoid infinite loop */
351 if (next_offset >= GlobalSize16(pSeg->hSeg)) break;
352 offset = next_offset;
353 } while (offset != 0xffff);
361 WARN_(fixup)("WARNING: %d: unknown ADDR TYPE %d, "
362 "TYPE %d, OFFSET %04x, TARGET %04x %04x\n",
363 i + 1, rep->address_type, rep->relocation_type,
364 rep->offset, rep->target1, rep->target2);
370 /***********************************************************************
373 BOOL NE_LoadAllSegments( NE_MODULE *pModule )
376 SEGTABLEENTRY * pSegTable = (SEGTABLEENTRY *) NE_SEG_TABLE(pModule);
378 if (pModule->flags & NE_FFLAGS_SELFLOAD)
382 /* Handle self-loading modules */
383 SELFLOADHEADER *selfloadheader;
384 HMODULE16 hselfload = GetModuleHandle16("WPROCS");
387 TRACE_(module)("%.*s is a self-loading module!\n",
388 *((BYTE*)pModule + pModule->name_table),
389 (char *)pModule + pModule->name_table + 1);
390 if (!NE_LoadSegment( pModule, 1 )) return FALSE;
391 selfloadheader = (SELFLOADHEADER *)
392 PTR_SEG_OFF_TO_LIN(SEL(pSegTable->hSeg), 0);
393 selfloadheader->EntryAddrProc = NE_GetEntryPoint(hselfload,27);
394 selfloadheader->MyAlloc = NE_GetEntryPoint(hselfload,28);
395 selfloadheader->SetOwner = NE_GetEntryPoint(GetModuleHandle16("KERNEL"),403);
396 pModule->self_loading_sel = SEL(GLOBAL_Alloc(GMEM_ZEROINIT, 0xFF00, pModule->self, FALSE, FALSE, FALSE));
397 oldstack = NtCurrentTeb()->cur_stack;
398 NtCurrentTeb()->cur_stack = PTR_SEG_OFF_TO_SEGPTR(pModule->self_loading_sel,
399 0xff00 - sizeof(STACK16FRAME) );
401 DuplicateHandle( GetCurrentProcess(), NE_OpenFile(pModule),
402 GetCurrentProcess(), &hf, 0, FALSE, DUPLICATE_SAME_ACCESS );
403 hFile16 = FILE_AllocDosHandle( hf );
404 TRACE_(dll)("CallBootAppProc(hModule=0x%04x,hf=0x%04x)\n",
405 pModule->self,hFile16);
406 Callbacks->CallBootAppProc(selfloadheader->BootApp, pModule->self,hFile16);
407 TRACE_(dll)("Return from CallBootAppProc\n");
409 NtCurrentTeb()->cur_stack = oldstack;
411 for (i = 2; i <= pModule->seg_count; i++)
412 if (!NE_LoadSegment( pModule, i )) return FALSE;
416 for (i = 1; i <= pModule->seg_count; i++)
417 if (!NE_LoadSegment( pModule, i )) return FALSE;
423 /***********************************************************************
424 * NE_FixupSegmentPrologs
426 * Fixup exported functions prologs of one segment
428 static void NE_FixupSegmentPrologs(NE_MODULE *pModule, WORD segnum)
430 SEGTABLEENTRY *pSegTable = NE_SEG_TABLE( pModule );
433 WORD dgroup, num_entries, sel = SEL(pSegTable[segnum-1].hSeg);
436 TRACE_(module)("(%d);\n", segnum);
438 if (pSegTable[segnum-1].flags & NE_SEGFLAGS_DATA)
440 pSegTable[segnum-1].flags |= NE_SEGFLAGS_LOADED;
444 if (!pModule->dgroup) return;
446 if (!(dgroup = SEL(pSegTable[pModule->dgroup-1].hSeg))) return;
448 pSeg = PTR_SEG_OFF_TO_LIN(sel, 0);
450 bundle = (ET_BUNDLE *)((BYTE *)pModule+pModule->entry_table);
453 TRACE_(module)("num_entries: %d, bundle: %p, next: %04x, pSeg: %p\n", bundle->last - bundle->first, bundle, bundle->next, pSeg);
454 if (!(num_entries = bundle->last - bundle->first))
456 entry = (ET_ENTRY *)((BYTE *)bundle+6);
457 while (num_entries--)
459 /*TRACE(module, "entry: %p, entry->segnum: %d, entry->offs: %04x\n", entry, entry->segnum, entry->offs);*/
460 if (entry->segnum == segnum)
462 pFunc = ((BYTE *)pSeg+entry->offs);
463 TRACE_(module)("pFunc: %p, *(DWORD *)pFunc: %08lx, num_entries: %d\n", pFunc, *(DWORD *)pFunc, num_entries);
464 if (*(pFunc+2) == 0x90)
466 if (*(WORD *)pFunc == 0x581e) /* push ds, pop ax */
468 TRACE_(module)("patch %04x:%04x -> mov ax, ds\n", sel, entry->offs);
469 *(WORD *)pFunc = 0xd88c; /* mov ax, ds */
472 if (*(WORD *)pFunc == 0xd88c)
474 if ((entry->flags & 2)) /* public data ? */
476 TRACE_(module)("patch %04x:%04x -> mov ax, dgroup [%04x]\n", sel, entry->offs, dgroup);
477 *pFunc = 0xb8; /* mov ax, */
478 *(WORD *)(pFunc+1) = dgroup;
481 if ((pModule->flags & NE_FFLAGS_MULTIPLEDATA)
482 && (entry->flags & 1)) /* exported ? */
484 TRACE_(module)("patch %04x:%04x -> nop, nop\n", sel, entry->offs);
485 *(WORD *)pFunc = 0x9090; /* nop, nop */
492 } while ( (bundle->next)
493 && (bundle = ((ET_BUNDLE *)((BYTE *)pModule + bundle->next))) );
497 /***********************************************************************
500 * Needed for self-loading modules.
502 DWORD WINAPI PatchCodeHandle16(HANDLE16 hSeg)
505 WORD sel = SEL(hSeg);
506 NE_MODULE *pModule = NE_GetPtr(FarGetOwner16(sel));
507 SEGTABLEENTRY *pSegTable = NE_SEG_TABLE(pModule);
509 TRACE_(module)("(%04x);\n", hSeg);
511 /* find the segment number of the module that belongs to hSeg */
512 for (segnum = 1; segnum <= pModule->seg_count; segnum++)
514 if (SEL(pSegTable[segnum-1].hSeg) == sel)
516 NE_FixupSegmentPrologs(pModule, segnum);
521 return MAKELONG(hSeg, sel);
525 /***********************************************************************
526 * NE_GetDLLInitParams
528 static VOID NE_GetDLLInitParams( NE_MODULE *pModule,
529 WORD *hInst, WORD *ds, WORD *heap )
531 SEGTABLEENTRY *pSegTable = NE_SEG_TABLE( pModule );
533 if (!(pModule->flags & NE_FFLAGS_SINGLEDATA))
535 if (pModule->flags & NE_FFLAGS_MULTIPLEDATA || pModule->dgroup)
538 ERR_(dll)("Library is not marked SINGLEDATA\n");
541 else /* DATA NONE DLL */
547 else /* DATA SINGLE DLL */
549 if (pModule->dgroup) {
550 *ds = SEL(pSegTable[pModule->dgroup-1].hSeg);
551 *heap = pModule->heap_size;
553 else /* hmm, DLL has no dgroup,
554 but why has it NE_FFLAGS_SINGLEDATA set ?
555 Buggy DLL compiler ? */
562 *hInst = *ds ? *ds : pModule->self;
566 /***********************************************************************
569 * Call the DLL initialization code
571 static BOOL NE_InitDLL( TDB* pTask, NE_MODULE *pModule )
573 SEGTABLEENTRY *pSegTable;
574 WORD hInst, ds, heap;
577 pSegTable = NE_SEG_TABLE( pModule );
579 if (!(pModule->flags & NE_FFLAGS_LIBMODULE) ||
580 (pModule->flags & NE_FFLAGS_WIN32)) return TRUE; /*not a library*/
582 /* Call USER signal handler for Win3.1 compatibility. */
583 TASK_CallTaskSignalProc( USIG16_DLL_LOAD, pModule->self );
585 if (!pModule->cs) return TRUE; /* no initialization code */
588 /* Registers at initialization must be:
590 * di library instance
591 * ds data segment if any
592 * es:si command line (always 0)
595 memset( &context, 0, sizeof(context) );
597 NE_GetDLLInitParams( pModule, &hInst, &ds, &heap );
599 ECX_reg(&context) = heap;
600 EDI_reg(&context) = hInst;
601 DS_reg(&context) = ds;
602 ES_reg(&context) = ds; /* who knows ... */
604 CS_reg(&context) = SEL(pSegTable[pModule->cs-1].hSeg);
605 EIP_reg(&context) = pModule->ip;
606 EBP_reg(&context) = OFFSETOF(NtCurrentTeb()->cur_stack) + (WORD)&((STACK16FRAME*)0)->bp;
609 pModule->cs = 0; /* Don't initialize it twice */
610 TRACE_(dll)("Calling LibMain, cs:ip=%04lx:%04lx ds=%04lx di=%04x cx=%04x\n",
611 CS_reg(&context), EIP_reg(&context), DS_reg(&context),
612 DI_reg(&context), CX_reg(&context) );
613 Callbacks->CallRegisterShortProc( &context, 0 );
617 /***********************************************************************
620 * Recursively initialize all DLLs (according to the order in which
621 * they where loaded).
623 void NE_InitializeDLLs( HMODULE16 hModule )
625 TDB* pTask = (TDB*)GlobalLock16(GetCurrentTask());
629 if (!(pModule = NE_GetPtr( hModule ))) return;
630 assert( !(pModule->flags & NE_FFLAGS_WIN32) );
632 if (pModule->dlls_to_init)
634 HGLOBAL16 to_init = pModule->dlls_to_init;
635 pModule->dlls_to_init = 0;
636 for (pDLL = (HMODULE16 *)GlobalLock16( to_init ); *pDLL; pDLL++)
638 NE_InitializeDLLs( *pDLL );
640 GlobalFree16( to_init );
642 NE_InitDLL( pTask, pModule );
646 /***********************************************************************
647 * NE_CallDllEntryPoint
649 * Call the DllEntryPoint of DLLs with subsystem >= 4.0
651 typedef DWORD WINAPI (*WinNEEntryProc)(DWORD,WORD,WORD,WORD,DWORD,WORD);
653 static void NE_CallDllEntryPoint( NE_MODULE *pModule, DWORD dwReason )
655 WORD hInst, ds, heap;
656 FARPROC16 entryPoint;
659 if (!(pModule->flags & NE_FFLAGS_LIBMODULE)) return;
660 if (!(pModule->flags & NE_FFLAGS_BUILTIN) && pModule->expected_version < 0x0400) return;
661 if (!(ordinal = NE_GetOrdinal( pModule->self, "DllEntryPoint" ))) return;
662 if (!(entryPoint = NE_GetEntryPoint( pModule->self, ordinal ))) return;
664 NE_GetDLLInitParams( pModule, &hInst, &ds, &heap );
666 TRACE_(dll)( "Calling %s DllEntryPoint, cs:ip=%04x:%04x\n",
667 NE_MODULE_NAME( pModule ),
668 SELECTOROF(entryPoint), OFFSETOF(entryPoint) );
670 if ( pModule->flags & NE_FFLAGS_BUILTIN )
672 WinNEEntryProc entryProc = (WinNEEntryProc)
673 ((ENTRYPOINT16 *)PTR_SEG_TO_LIN( entryPoint ))->target;
675 entryProc( dwReason, hInst, ds, heap, 0, 0 );
679 LPBYTE stack = (LPBYTE)CURRENT_STACK16;
682 memset( &context, 0, sizeof(context) );
683 DS_reg(&context) = ds;
684 ES_reg(&context) = ds; /* who knows ... */
686 CS_reg(&context) = HIWORD(entryPoint);
687 EIP_reg(&context) = LOWORD(entryPoint);
688 EBP_reg(&context) = OFFSETOF( NtCurrentTeb()->cur_stack )
689 + (WORD)&((STACK16FRAME*)0)->bp;
691 *(DWORD *)(stack - 4) = dwReason; /* dwReason */
692 *(WORD *) (stack - 6) = hInst; /* hInst */
693 *(WORD *) (stack - 8) = ds; /* wDS */
694 *(WORD *) (stack - 10) = heap; /* wHeapSize */
695 *(DWORD *)(stack - 14) = 0; /* dwReserved1 */
696 *(WORD *) (stack - 16) = 0; /* wReserved2 */
698 Callbacks->CallRegisterShortProc( &context, 16 );
702 /***********************************************************************
703 * NE_DllProcessAttach
705 * Call the DllEntryPoint of all modules this one (recursively)
706 * depends on, according to the order in which they were loaded.
708 * Note that --as opposed to the PE module case-- there is no notion
709 * of 'module loaded into a process' for NE modules, and hence we
710 * have no place to store the fact that the DllEntryPoint of a
711 * given module was already called on behalf of this process (e.g.
712 * due to some earlier LoadLibrary16 call).
714 * Thus, we just call the DllEntryPoint twice in that case. Win9x
715 * appears to behave this way as well ...
717 * This routine must only be called with the Win16Lock held.
719 * FIXME: We should actually abort loading in case the DllEntryPoint
723 void NE_DllProcessAttach( HMODULE16 hModule )
729 if (!(pModule = NE_GetPtr( hModule ))) return;
730 assert( !(pModule->flags & NE_FFLAGS_WIN32) );
732 /* Check for recursive call */
733 if ( pModule->misc_flags & 0x80 ) return;
735 TRACE_(dll)("(%s) - START\n", NE_MODULE_NAME(pModule) );
737 /* Tag current module to prevent recursive loop */
738 pModule->misc_flags |= 0x80;
740 /* Recursively attach all DLLs this one depends on */
741 pModRef = NE_MODULE_TABLE( pModule );
742 for ( i = 0; i < pModule->modref_count; i++ )
744 NE_DllProcessAttach( (HMODULE16)pModRef[i] );
746 /* Call DLL entry point */
747 NE_CallDllEntryPoint( pModule, DLL_PROCESS_ATTACH );
749 /* Remove recursion flag */
750 pModule->misc_flags &= ~0x80;
752 TRACE_(dll)("(%s) - END\n", NE_MODULE_NAME(pModule) );
756 /***********************************************************************
759 * This function translates NE segment flags to GlobalAlloc flags
761 static WORD NE_Ne2MemFlags(WORD flags)
765 if (flags & NE_SEGFLAGS_DISCARDABLE)
766 memflags |= GMEM_DISCARDABLE;
767 if (flags & NE_SEGFLAGS_MOVEABLE ||
768 ( ! (flags & NE_SEGFLAGS_DATA) &&
769 ! (flags & NE_SEGFLAGS_LOADED) &&
770 ! (flags & NE_SEGFLAGS_ALLOCATED)
773 memflags |= GMEM_MOVEABLE;
774 memflags |= GMEM_ZEROINIT;
776 memflags = GMEM_ZEROINIT | GMEM_FIXED;
781 /***********************************************************************
782 * NE_AllocateSegment (WPROCS.26)
784 * MyAlloc() function for self-loading apps.
786 DWORD WINAPI NE_AllocateSegment( WORD wFlags, WORD wSize, WORD wElem )
788 WORD size = wSize << wElem;
791 if (wSize || (wFlags & NE_SEGFLAGS_MOVEABLE))
792 hMem = GlobalAlloc16( NE_Ne2MemFlags(wFlags), size);
794 if ( ((wFlags & 0x7) != 0x1) && /* DATA */
795 ((wFlags & 0x7) != 0x7) ) /* DATA|ALLOCATED|LOADED */
797 WORD hSel = SEL(hMem);
798 WORD access = SelectorAccessRights16(hSel,0,0);
800 access |= 2<<2; /* SEGMENT_CODE */
801 SelectorAccessRights16(hSel,1,access);
804 return MAKELONG( hMem, SEL(hMem) );
806 return MAKELONG( 0, hMem );
809 /***********************************************************************
812 HINSTANCE16 NE_GetInstance( NE_MODULE *pModule )
814 if ( !pModule->dgroup )
815 return pModule->self;
818 SEGTABLEENTRY *pSegment;
819 pSegment = NE_SEG_TABLE( pModule ) + pModule->dgroup - 1;
821 return SEL(pSegment->hSeg);
825 /***********************************************************************
828 BOOL NE_CreateSegment( NE_MODULE *pModule, int segnum )
830 SEGTABLEENTRY *pSegment = NE_SEG_TABLE( pModule ) + segnum - 1;
833 assert( !(pModule->flags & NE_FFLAGS_WIN32) );
835 if ( segnum < 1 || segnum > pModule->seg_count )
838 if ( (pModule->flags & NE_FFLAGS_SELFLOAD) && segnum != 1 )
839 return TRUE; /* selfloader allocates segment itself */
841 if ( (pSegment->flags & NE_SEGFLAGS_ALLOCATED) && segnum != pModule->dgroup )
842 return TRUE; /* all but DGROUP only allocated once */
844 minsize = pSegment->minsize ? pSegment->minsize : 0x10000;
845 if ( segnum == pModule->ss ) minsize += pModule->stack_size;
846 if ( segnum == pModule->dgroup ) minsize += pModule->heap_size;
848 pSegment->hSeg = GLOBAL_Alloc( NE_Ne2MemFlags(pSegment->flags),
849 minsize, pModule->self,
850 !(pSegment->flags & NE_SEGFLAGS_DATA),
851 (pSegment->flags & NE_SEGFLAGS_32BIT) != 0,
852 FALSE /*pSegment->flags & NE_SEGFLAGS_READONLY*/ );
853 if (!pSegment->hSeg) return FALSE;
855 pSegment->flags |= NE_SEGFLAGS_ALLOCATED;
859 /***********************************************************************
860 * NE_CreateAllSegments
862 BOOL NE_CreateAllSegments( NE_MODULE *pModule )
865 for ( i = 1; i <= pModule->seg_count; i++ )
866 if ( !NE_CreateSegment( pModule, i ) )
869 pModule->dgroup_entry = pModule->dgroup ? pModule->seg_table +
870 (pModule->dgroup - 1) * sizeof(SEGTABLEENTRY) : 0;
875 /**********************************************************************
876 * IsSharedSelector (KERNEL.345)
878 BOOL16 WINAPI IsSharedSelector16( HANDLE16 selector )
880 /* Check whether the selector belongs to a DLL */
881 NE_MODULE *pModule = NE_GetPtr( selector );
882 if (!pModule) return FALSE;
883 return (pModule->flags & NE_FFLAGS_LIBMODULE) != 0;