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 "debugtools.h"
32 DECLARE_DEBUG_CHANNEL(dll)
33 DECLARE_DEBUG_CHANNEL(fixup)
34 DECLARE_DEBUG_CHANNEL(module)
35 DECLARE_DEBUG_CHANNEL(segment)
37 #define SEL(x) GlobalHandleToSel16(x)
39 /***********************************************************************
42 static const char *NE_GetRelocAddrName( BYTE addr_type, int additive )
44 switch(addr_type & 0x7f)
46 case NE_RADDR_LOWBYTE: return additive ? "BYTE add" : "BYTE";
47 case NE_RADDR_OFFSET16: return additive ? "OFFSET16 add" : "OFFSET16";
48 case NE_RADDR_POINTER32: return additive ? "POINTER32 add" : "POINTER32";
49 case NE_RADDR_SELECTOR: return additive ? "SELECTOR add" : "SELECTOR";
50 case NE_RADDR_POINTER48: return additive ? "POINTER48 add" : "POINTER48";
51 case NE_RADDR_OFFSET32: return additive ? "OFFSET32 add" : "OFFSET32";
57 /***********************************************************************
60 BOOL NE_LoadSegment( NE_MODULE *pModule, WORD segnum )
62 SEGTABLEENTRY *pSegTable, *pSeg;
64 WORD count, i, offset, next_offset;
66 FARPROC16 address = 0;
69 struct relocation_entry_s *rep, *reloc_entries;
75 int ordinal, additive;
78 pSegTable = NE_SEG_TABLE( pModule );
79 pSeg = pSegTable + segnum - 1;
81 if (pSeg->flags & NE_SEGFLAGS_LOADED) /* already loaded ? */
84 if (!pSeg->filepos) return TRUE; /* No file image, just return */
86 pModuleTable = NE_MODULE_TABLE( pModule );
88 hf = NE_OpenFile( pModule );
89 TRACE_(module)("Loading segment %d, hSeg=%04x, flags=%04x\n",
90 segnum, pSeg->hSeg, pSeg->flags );
91 SetFilePointer( hf, pSeg->filepos << pModule->alignment, NULL, SEEK_SET );
92 if (pSeg->size) size = pSeg->size;
93 else size = pSeg->minsize ? pSeg->minsize : 0x10000;
94 mem = GlobalLock16(pSeg->hSeg);
95 if (pModule->flags & NE_FFLAGS_SELFLOAD && segnum > 1)
97 /* Implement self-loading segments */
98 SELFLOADHEADER *selfloadheader;
99 STACK16FRAME *stack16Top;
101 WORD old_hSeg, new_hSeg;
102 THDB *thdb = THREAD_Current();
106 selfloadheader = (SELFLOADHEADER *)
107 PTR_SEG_OFF_TO_LIN(SEL(pSegTable->hSeg),0);
108 oldstack = thdb->cur_stack;
109 old_hSeg = pSeg->hSeg;
110 thdb->cur_stack = PTR_SEG_OFF_TO_SEGPTR(pModule->self_loading_sel,
111 0xff00 - sizeof(*stack16Top));
112 stack16Top = (STACK16FRAME *)PTR_SEG_TO_LIN(thdb->cur_stack);
113 stack16Top->frame32 = 0;
114 stack16Top->ds = stack16Top->es = pModule->self_loading_sel;
115 stack16Top->entry_point = 0;
116 stack16Top->entry_ip = 0;
117 stack16Top->entry_cs = 0;
121 TRACE_(dll)("CallLoadAppSegProc(hmodule=0x%04x,hf=0x%04x,segnum=%d\n",
122 pModule->self,hf,segnum );
123 DuplicateHandle( GetCurrentProcess(), hf, GetCurrentProcess(), &hFile32,
124 0, FALSE, DUPLICATE_SAME_ACCESS );
125 hFile16 = FILE_AllocDosHandle( hFile32 );
126 new_hSeg = Callbacks->CallLoadAppSegProc(selfloadheader->LoadAppSeg,
127 pModule->self, hFile16,
129 TRACE_(dll)("Ret CallLoadAppSegProc: hSeg = 0x%04x\n",new_hSeg);
130 _lclose16( hFile16 );
131 if (SEL(new_hSeg) != SEL(old_hSeg)) {
132 /* Self loaders like creating their own selectors;
133 * they love asking for trouble to Wine developers
135 if (segnum == pModule->dgroup) {
136 memcpy(PTR_SEG_OFF_TO_LIN(SEL(old_hSeg),0),
137 PTR_SEG_OFF_TO_LIN(SEL(new_hSeg),0),
138 pSeg->minsize ? pSeg->minsize : 0x10000);
139 FreeSelector16(SEL(new_hSeg));
140 pSeg->hSeg = old_hSeg;
141 TRACE_(module)("New hSeg allocated for dgroup segment:Old=%d,New=%d\n",
144 FreeSelector16(SEL(pSeg->hSeg));
145 pSeg->hSeg = new_hSeg;
149 thdb->cur_stack = oldstack;
151 else if (!(pSeg->flags & NE_SEGFLAGS_ITERATED))
152 ReadFile(hf, mem, size, &res, NULL);
155 The following bit of code for "iterated segments" was written without
156 any documentation on the format of these segments. It seems to work,
157 but may be missing something. If you have any doc please either send
158 it to me or fix the code yourself. gfm@werple.mira.net.au
160 char* buff = xmalloc(size);
162 ReadFile(hf, buff, size, &res, NULL);
163 while(curr < buff + size) {
164 unsigned int rept = *((short*) curr)++;
165 unsigned int len = *((short*) curr)++;
166 for(; rept > 0; rept--) {
169 for(byte = 0; byte < len; byte++)
177 pSeg->flags |= NE_SEGFLAGS_LOADED;
178 if (!(pSeg->flags & NE_SEGFLAGS_RELOC_DATA))
179 return TRUE; /* No relocation data, we are done */
181 ReadFile(hf, &count, sizeof(count), &res, NULL);
182 if (!count) return TRUE;
184 TRACE_(fixup)("Fixups for %.*s, segment %d, hSeg %04x\n",
185 *((BYTE *)pModule + pModule->name_table),
186 (char *)pModule + pModule->name_table + 1,
187 segnum, pSeg->hSeg );
188 TRACE_(segment)("Fixups for %.*s, segment %d, hSeg %04x\n",
189 *((BYTE *)pModule + pModule->name_table),
190 (char *)pModule + pModule->name_table + 1,
191 segnum, pSeg->hSeg );
193 reloc_entries = (struct relocation_entry_s *)xmalloc(count * sizeof(struct relocation_entry_s));
194 if (!ReadFile( hf, reloc_entries, count * sizeof(struct relocation_entry_s), &res, NULL) ||
195 (res != count * sizeof(struct relocation_entry_s)))
197 WARN_(fixup)("Unable to read relocation information\n" );
202 * Go through the relocation table one entry at a time.
205 for (i = 0; i < count; i++, rep++)
208 * Get the target address corresponding to this entry.
211 /* If additive, there is no target chain list. Instead, add source
213 additive = rep->relocation_type & NE_RELFLAG_ADDITIVE;
214 rep->relocation_type &= 0x3;
216 switch (rep->relocation_type)
218 case NE_RELTYPE_ORDINAL:
219 module = pModuleTable[rep->target1-1];
220 ordinal = rep->target2;
221 address = NE_GetEntryPoint( module, ordinal );
224 NE_MODULE *pTarget = NE_GetPtr( module );
226 WARN_(module)("Module not found: %04x, reference %d of module %*.*s\n",
227 module, rep->target1,
228 *((BYTE *)pModule + pModule->name_table),
229 *((BYTE *)pModule + pModule->name_table),
230 (char *)pModule + pModule->name_table + 1 );
233 ERR_(fixup)("No implementation for %.*s.%d, setting to 0xdeadbeef\n",
234 *((BYTE *)pTarget + pTarget->name_table),
235 (char *)pTarget + pTarget->name_table + 1,
237 address = (FARPROC16)0xdeadbeef;
242 NE_MODULE *pTarget = NE_GetPtr( module );
243 TRACE_(fixup)("%d: %.*s.%d=%04x:%04x %s\n", i + 1,
244 *((BYTE *)pTarget + pTarget->name_table),
245 (char *)pTarget + pTarget->name_table + 1,
246 ordinal, HIWORD(address), LOWORD(address),
247 NE_GetRelocAddrName( rep->address_type, additive ) );
251 case NE_RELTYPE_NAME:
252 module = pModuleTable[rep->target1-1];
253 func_name = (char *)pModule + pModule->import_table + rep->target2;
254 memcpy( buffer, func_name+1, *func_name );
255 buffer[*func_name] = '\0';
257 ordinal = NE_GetOrdinal( module, func_name );
258 address = NE_GetEntryPoint( module, ordinal );
260 if (ERR_ON(fixup) && !address)
262 NE_MODULE *pTarget = NE_GetPtr( module );
263 ERR_(fixup)("No implementation for %.*s.%s, setting to 0xdeadbeef\n",
264 *((BYTE *)pTarget + pTarget->name_table),
265 (char *)pTarget + pTarget->name_table + 1, func_name );
267 if (!address) address = (FARPROC16) 0xdeadbeef;
270 NE_MODULE *pTarget = NE_GetPtr( module );
271 TRACE_(fixup)("%d: %.*s.%s=%04x:%04x %s\n", i + 1,
272 *((BYTE *)pTarget + pTarget->name_table),
273 (char *)pTarget + pTarget->name_table + 1,
274 func_name, HIWORD(address), LOWORD(address),
275 NE_GetRelocAddrName( rep->address_type, additive ) );
279 case NE_RELTYPE_INTERNAL:
280 if ((rep->target1 & 0xff) == 0xff)
282 address = NE_GetEntryPoint( pModule->self, rep->target2 );
286 address = (FARPROC16)PTR_SEG_OFF_TO_SEGPTR( SEL(pSegTable[rep->target1-1].hSeg), rep->target2 );
289 TRACE_(fixup)("%d: %04x:%04x %s\n",
290 i + 1, HIWORD(address), LOWORD(address),
291 NE_GetRelocAddrName( rep->address_type, additive ) );
294 case NE_RELTYPE_OSFIXUP:
295 /* Relocation type 7:
297 * These appear to be used as fixups for the Windows
298 * floating point emulator. Let's just ignore them and
299 * try to use the hardware floating point. Linux should
300 * successfully emulate the coprocessor if it doesn't
303 TRACE_(fixup)("%d: TYPE %d, OFFSET %04x, TARGET %04x %04x %s\n",
304 i + 1, rep->relocation_type, rep->offset,
305 rep->target1, rep->target2,
306 NE_GetRelocAddrName( rep->address_type, additive ) );
310 offset = rep->offset;
312 /* Apparently, high bit of address_type is sometimes set; */
313 /* we ignore it for now */
314 if (rep->address_type > NE_RADDR_OFFSET32)
317 GetModuleName16( pModule->self, module, sizeof(module) );
318 ERR_(fixup)("WARNING: module %s: unknown reloc addr type = 0x%02x. Please report.\n",
319 module, rep->address_type );
324 sp = PTR_SEG_OFF_TO_LIN( SEL(pSeg->hSeg), offset );
325 TRACE_(fixup)(" %04x:%04x\n", offset, *sp );
326 switch (rep->address_type & 0x7f)
328 case NE_RADDR_LOWBYTE:
329 *(BYTE *)sp += LOBYTE((int)address);
331 case NE_RADDR_OFFSET16:
332 *sp += LOWORD(address);
334 case NE_RADDR_POINTER32:
335 *sp += LOWORD(address);
336 *(sp+1) = HIWORD(address);
338 case NE_RADDR_SELECTOR:
339 /* Borland creates additive records with offset zero. Strange, but OK */
341 ERR_(fixup)("Additive selector to %04x.Please report\n",*sp);
343 *sp = HIWORD(address);
349 else /* non-additive fixup */
353 sp = PTR_SEG_OFF_TO_LIN( SEL(pSeg->hSeg), offset );
355 TRACE_(fixup)(" %04x:%04x\n", offset, *sp );
356 switch (rep->address_type & 0x7f)
358 case NE_RADDR_LOWBYTE:
359 *(BYTE *)sp = LOBYTE((int)address);
361 case NE_RADDR_OFFSET16:
362 *sp = LOWORD(address);
364 case NE_RADDR_POINTER32:
365 *(FARPROC16 *)sp = address;
367 case NE_RADDR_SELECTOR:
368 *sp = SELECTOROF(address);
373 if (next_offset == offset) break; /* avoid infinite loop */
374 if (next_offset >= GlobalSize16(pSeg->hSeg)) break;
375 offset = next_offset;
376 } while (offset != 0xffff);
384 WARN_(fixup)("WARNING: %d: unknown ADDR TYPE %d, "
385 "TYPE %d, OFFSET %04x, TARGET %04x %04x\n",
386 i + 1, rep->address_type, rep->relocation_type,
387 rep->offset, rep->target1, rep->target2);
393 /***********************************************************************
396 BOOL NE_LoadAllSegments( NE_MODULE *pModule )
399 SEGTABLEENTRY * pSegTable = (SEGTABLEENTRY *) NE_SEG_TABLE(pModule);
401 if (pModule->flags & NE_FFLAGS_SELFLOAD)
405 /* Handle self-loading modules */
406 SELFLOADHEADER *selfloadheader;
407 STACK16FRAME *stack16Top;
408 THDB *thdb = THREAD_Current();
409 HMODULE16 hselfload = GetModuleHandle16("WPROCS");
411 WORD saved_hSeg = pSegTable[pModule->dgroup - 1].hSeg;
413 TRACE_(module)("%.*s is a self-loading module!\n",
414 *((BYTE*)pModule + pModule->name_table),
415 (char *)pModule + pModule->name_table + 1);
416 if (!NE_LoadSegment( pModule, 1 )) return FALSE;
417 selfloadheader = (SELFLOADHEADER *)
418 PTR_SEG_OFF_TO_LIN(SEL(pSegTable->hSeg), 0);
419 selfloadheader->EntryAddrProc = NE_GetEntryPoint(hselfload,27);
420 selfloadheader->MyAlloc = NE_GetEntryPoint(hselfload,28);
421 selfloadheader->SetOwner = NE_GetEntryPoint(GetModuleHandle16("KERNEL"),403);
422 pModule->self_loading_sel = SEL(GLOBAL_Alloc(GMEM_ZEROINIT, 0xFF00, pModule->self, FALSE, FALSE, FALSE));
423 oldstack = thdb->cur_stack;
424 thdb->cur_stack = PTR_SEG_OFF_TO_SEGPTR(pModule->self_loading_sel,
425 0xff00 - sizeof(*stack16Top) );
426 stack16Top = (STACK16FRAME *)PTR_SEG_TO_LIN(thdb->cur_stack);
427 stack16Top->frame32 = 0;
429 stack16Top->ds = stack16Top->es = pModule->self_loading_sel;
430 stack16Top->entry_point = 0;
431 stack16Top->entry_ip = 0;
432 stack16Top->entry_cs = 0;
437 DuplicateHandle( GetCurrentProcess(), NE_OpenFile(pModule),
438 GetCurrentProcess(), &hf, 0, FALSE, DUPLICATE_SAME_ACCESS );
439 hFile16 = FILE_AllocDosHandle( hf );
440 TRACE_(dll)("CallBootAppProc(hModule=0x%04x,hf=0x%04x)\n",
441 pModule->self,hFile16);
442 Callbacks->CallBootAppProc(selfloadheader->BootApp, pModule->self,hFile16);
443 TRACE_(dll)("Return from CallBootAppProc\n");
445 /* some BootApp procs overwrite the segment handle of dgroup */
446 pSegTable[pModule->dgroup - 1].hSeg = saved_hSeg;
447 thdb->cur_stack = oldstack;
449 for (i = 2; i <= pModule->seg_count; i++)
450 if (!NE_LoadSegment( pModule, i )) return FALSE;
454 for (i = 1; i <= pModule->seg_count; i++)
455 if (!NE_LoadSegment( pModule, i )) return FALSE;
461 /***********************************************************************
462 * NE_FixupSegmentPrologs
464 * Fixup exported functions prologs of one segment
466 void NE_FixupSegmentPrologs(NE_MODULE *pModule, WORD segnum)
468 SEGTABLEENTRY *pSegTable = NE_SEG_TABLE( pModule );
471 WORD dgroup, num_entries, sel = SEL(pSegTable[segnum-1].hSeg);
474 TRACE_(module)("(%d);\n", segnum);
476 if (pSegTable[segnum-1].flags & NE_SEGFLAGS_DATA)
478 pSegTable[segnum-1].flags |= NE_SEGFLAGS_LOADED;
481 if (!(dgroup = SEL(pSegTable[pModule->dgroup-1].hSeg)))
484 pSeg = PTR_SEG_OFF_TO_LIN(sel, 0);
486 bundle = (ET_BUNDLE *)((BYTE *)pModule+pModule->entry_table);
489 TRACE_(module)("num_entries: %d, bundle: %p, next: %04x, pSeg: %p\n", bundle->last - bundle->first, bundle, bundle->next, pSeg);
490 if (!(num_entries = bundle->last - bundle->first))
492 entry = (ET_ENTRY *)((BYTE *)bundle+6);
493 while (num_entries--)
495 /*TRACE(module, "entry: %p, entry->segnum: %d, entry->offs: %04x\n", entry, entry->segnum, entry->offs);*/
496 if (entry->segnum == segnum)
498 pFunc = ((BYTE *)pSeg+entry->offs);
499 TRACE_(module)("pFunc: %p, *(DWORD *)pFunc: %08lx, num_entries: %d\n", pFunc, *(DWORD *)pFunc, num_entries);
500 if (*(pFunc+2) == 0x90)
502 if (*(WORD *)pFunc == 0x581e) /* push ds, pop ax */
504 TRACE_(module)("patch %04x:%04x -> mov ax, ds\n", sel, entry->offs);
505 *(WORD *)pFunc = 0xd88c; /* mov ax, ds */
508 if (*(WORD *)pFunc == 0xd88c)
510 if ((entry->flags & 2)) /* public data ? */
512 TRACE_(module)("patch %04x:%04x -> mov ax, dgroup [%04x]\n", sel, entry->offs, dgroup);
513 *pFunc = 0xb8; /* mov ax, */
514 *(WORD *)(pFunc+1) = dgroup;
517 if ((pModule->flags & NE_FFLAGS_MULTIPLEDATA)
518 && (entry->flags & 1)) /* exported ? */
520 TRACE_(module)("patch %04x:%04x -> nop, nop\n", sel, entry->offs);
521 *(WORD *)pFunc = 0x9090; /* nop, nop */
528 } while ( (bundle->next)
529 && (bundle = ((ET_BUNDLE *)((BYTE *)pModule + bundle->next))) );
533 /***********************************************************************
536 * Needed for self-loading modules.
538 DWORD WINAPI PatchCodeHandle16(HANDLE16 hSeg)
541 WORD sel = SEL(hSeg);
542 NE_MODULE *pModule = NE_GetPtr(FarGetOwner16(sel));
543 SEGTABLEENTRY *pSegTable = NE_SEG_TABLE(pModule);
545 TRACE_(module)("(%04x);\n", hSeg);
547 /* find the segment number of the module that belongs to hSeg */
548 for (segnum = 1; segnum <= pModule->seg_count; segnum++)
550 if (SEL(pSegTable[segnum-1].hSeg) == sel)
552 NE_FixupSegmentPrologs(pModule, segnum);
557 return MAKELONG(hSeg, sel);
560 /***********************************************************************
563 * Fixup the exported functions prologs.
565 void NE_FixupPrologs( NE_MODULE *pModule )
569 TRACE_(module)("(%04x)\n", pModule->self );
571 if (pModule->flags & NE_FFLAGS_SELFLOAD)
572 NE_FixupSegmentPrologs(pModule, 1);
574 for (segnum=1; segnum <= pModule->seg_count; segnum++)
575 NE_FixupSegmentPrologs(pModule, segnum);
578 /***********************************************************************
579 * NE_GetDLLInitParams
581 static VOID NE_GetDLLInitParams( NE_MODULE *pModule,
582 WORD *hInst, WORD *ds, WORD *heap )
584 SEGTABLEENTRY *pSegTable = NE_SEG_TABLE( pModule );
586 if (!(pModule->flags & NE_FFLAGS_SINGLEDATA))
588 if (pModule->flags & NE_FFLAGS_MULTIPLEDATA || pModule->dgroup)
591 ERR_(dll)("Library is not marked SINGLEDATA\n");
594 else /* DATA NONE DLL */
600 else /* DATA SINGLE DLL */
602 if (pModule->dgroup) {
603 *ds = SEL(pSegTable[pModule->dgroup-1].hSeg);
604 *heap = pModule->heap_size;
606 else /* hmm, DLL has no dgroup,
607 but why has it NE_FFLAGS_SINGLEDATA set ?
608 Buggy DLL compiler ? */
615 *hInst = *ds ? *ds : pModule->self;
619 /***********************************************************************
622 * Call the DLL initialization code
624 static BOOL NE_InitDLL( TDB* pTask, NE_MODULE *pModule )
626 SEGTABLEENTRY *pSegTable;
627 WORD hInst, ds, heap;
630 pSegTable = NE_SEG_TABLE( pModule );
632 if (!(pModule->flags & NE_FFLAGS_LIBMODULE) ||
633 (pModule->flags & NE_FFLAGS_WIN32)) return TRUE; /*not a library*/
635 /* Call USER signal handler for Win3.1 compatibility. */
636 if (pTask && pTask->userhandler)
637 pTask->userhandler( pModule->self, USIG16_DLL_LOAD, 0,
638 pTask->hInstance, pTask->hQueue );
640 if (!pModule->cs) return TRUE; /* no initialization code */
643 /* Registers at initialization must be:
645 * di library instance
646 * ds data segment if any
647 * es:si command line (always 0)
650 memset( &context, 0, sizeof(context) );
652 NE_GetDLLInitParams( pModule, &hInst, &ds, &heap );
654 ECX_reg(&context) = heap;
655 EDI_reg(&context) = hInst;
656 DS_reg(&context) = ds;
657 ES_reg(&context) = ds; /* who knows ... */
659 CS_reg(&context) = SEL(pSegTable[pModule->cs-1].hSeg);
660 EIP_reg(&context) = pModule->ip;
661 EBP_reg(&context) = OFFSETOF(THREAD_Current()->cur_stack)
662 + (WORD)&((STACK16FRAME*)0)->bp;
665 pModule->cs = 0; /* Don't initialize it twice */
666 TRACE_(dll)("Calling LibMain, cs:ip=%04lx:%04x ds=%04lx di=%04x cx=%04x\n",
667 CS_reg(&context), IP_reg(&context), DS_reg(&context),
668 DI_reg(&context), CX_reg(&context) );
669 Callbacks->CallRegisterShortProc( &context, 0 );
673 /***********************************************************************
674 * NE_CallDllEntryPoint
676 * Call the DllEntryPoint of DLLs with subsystem >= 4.0
679 static void NE_CallDllEntryPoint( NE_MODULE *pModule, DWORD dwReason )
681 WORD hInst, ds, heap;
682 FARPROC16 entryPoint;
685 THDB *thdb = THREAD_Current();
686 LPBYTE stack = (LPBYTE)THREAD_STACK16(thdb);
688 if (!(pModule->flags & NE_FFLAGS_BUILTIN) && pModule->expected_version < 0x0400) return;
689 if (!(ordinal = NE_GetOrdinal( pModule->self, "DllEntryPoint" ))) return;
690 if (!(entryPoint = NE_GetEntryPoint( pModule->self, ordinal ))) return;
692 memset( &context, 0, sizeof(context) );
694 NE_GetDLLInitParams( pModule, &hInst, &ds, &heap );
696 DS_reg(&context) = ds;
697 ES_reg(&context) = ds; /* who knows ... */
699 CS_reg(&context) = HIWORD(entryPoint);
700 IP_reg(&context) = LOWORD(entryPoint);
701 EBP_reg(&context) = OFFSETOF( thdb->cur_stack )
702 + (WORD)&((STACK16FRAME*)0)->bp;
704 *(DWORD *)(stack - 4) = dwReason; /* dwReason */
705 *(WORD *) (stack - 6) = hInst; /* hInst */
706 *(WORD *) (stack - 8) = ds; /* wDS */
707 *(WORD *) (stack - 10) = heap; /* wHeapSize */
708 *(DWORD *)(stack - 14) = 0; /* dwReserved1 */
709 *(WORD *) (stack - 16) = 0; /* wReserved2 */
711 TRACE_(dll)("Calling DllEntryPoint, cs:ip=%04lx:%04x\n",
712 CS_reg(&context), IP_reg(&context));
714 Callbacks->CallRegisterShortProc( &context, 16 );
718 /***********************************************************************
721 * Recursively initialize all DLLs (according to the order in which
722 * they where loaded).
724 void NE_InitializeDLLs( HMODULE16 hModule )
726 TDB* pTask = (TDB*)GlobalLock16(GetCurrentTask());
730 if (!(pModule = NE_GetPtr( hModule ))) return;
731 assert( !(pModule->flags & NE_FFLAGS_WIN32) );
733 if (pModule->dlls_to_init)
735 HGLOBAL16 to_init = pModule->dlls_to_init;
736 pModule->dlls_to_init = 0;
737 for (pDLL = (HMODULE16 *)GlobalLock16( to_init ); *pDLL; pDLL++)
739 NE_InitializeDLLs( *pDLL );
741 GlobalFree16( to_init );
743 NE_InitDLL( pTask, pModule );
744 NE_CallDllEntryPoint( pModule, DLL_PROCESS_ATTACH );
748 /***********************************************************************
751 * If lib_only is TRUE, handle the module like a library even if it is a .EXE
753 HINSTANCE16 NE_CreateInstance( NE_MODULE *pModule, HINSTANCE16 *prev,
756 SEGTABLEENTRY *pSegment;
758 HINSTANCE16 hNewInstance;
760 if (pModule->dgroup == 0)
762 if (prev) *prev = pModule->self;
763 return pModule->self;
766 pSegment = NE_SEG_TABLE( pModule ) + pModule->dgroup - 1;
767 if (prev) *prev = SEL(pSegment->hSeg);
769 /* if it's a library, create a new instance only the first time */
772 if (pModule->flags & NE_FFLAGS_LIBMODULE) return SEL(pSegment->hSeg);
773 if (lib_only) return SEL(pSegment->hSeg);
776 minsize = pSegment->minsize ? pSegment->minsize : 0x10000;
777 if (pModule->ss == pModule->dgroup) minsize += pModule->stack_size;
778 minsize += pModule->heap_size;
779 hNewInstance = GLOBAL_Alloc( GMEM_ZEROINIT | GMEM_FIXED, minsize,
780 pModule->self, FALSE, FALSE, FALSE );
781 if (!hNewInstance) return 0;
782 pSegment->hSeg = hNewInstance;
783 pSegment->flags |= NE_SEGFLAGS_ALLOCATED;
788 /***********************************************************************
791 * This function translates NE segment flags to GlobalAlloc flags
793 static WORD NE_Ne2MemFlags(WORD flags)
797 if (flags & NE_SEGFLAGS_DISCARDABLE)
798 memflags |= GMEM_DISCARDABLE;
799 if (flags & NE_SEGFLAGS_MOVEABLE ||
800 ( ! (flags & NE_SEGFLAGS_DATA) &&
801 ! (flags & NE_SEGFLAGS_LOADED) &&
802 ! (flags & NE_SEGFLAGS_ALLOCATED)
805 memflags |= GMEM_MOVEABLE;
806 memflags |= GMEM_ZEROINIT;
808 memflags = GMEM_ZEROINIT | GMEM_FIXED;
813 /***********************************************************************
814 * NE_AllocateSegment (WPROCS.26)
816 * MyAlloc() function for self-loading apps.
818 DWORD WINAPI NE_AllocateSegment( WORD wFlags, WORD wSize, WORD wElem )
820 WORD size = wSize << wElem;
823 if (wSize || (wFlags & NE_SEGFLAGS_MOVEABLE))
824 hMem = GlobalAlloc16( NE_Ne2MemFlags(wFlags), size);
826 if ( ((wFlags & 0x7) != 0x1) && /* DATA */
827 ((wFlags & 0x7) != 0x7) ) /* DATA|ALLOCATED|LOADED */
829 WORD hSel = SEL(hMem);
830 WORD access = SelectorAccessRights16(hSel,0,0);
832 access |= 2<<2; /* SEGMENT_CODE */
833 SelectorAccessRights16(hSel,1,access);
836 return MAKELONG( hMem, SEL(hMem) );
838 return MAKELONG( 0, hMem );
842 /***********************************************************************
845 BOOL NE_CreateSegments( NE_MODULE *pModule )
847 SEGTABLEENTRY *pSegment;
848 int i, minsize, seg_count;
850 assert( !(pModule->flags & NE_FFLAGS_WIN32) );
852 pSegment = NE_SEG_TABLE( pModule );
854 if (pModule->flags & NE_FFLAGS_SELFLOAD)
857 seg_count = pModule->seg_count;
858 for (i = 1; i <= seg_count; i++, pSegment++)
860 minsize = pSegment->minsize ? pSegment->minsize : 0x10000;
861 if (i == pModule->ss) minsize += pModule->stack_size;
862 /* The DGROUP is allocated by NE_CreateInstance */
863 if (i == pModule->dgroup) continue;
864 pSegment->hSeg = GLOBAL_Alloc( NE_Ne2MemFlags(pSegment->flags),
865 minsize, pModule->self,
866 !(pSegment->flags & NE_SEGFLAGS_DATA),
868 FALSE /*pSegment->flags & NE_SEGFLAGS_READONLY*/ );
869 if (!pSegment->hSeg) return FALSE;
870 pSegment->flags |= NE_SEGFLAGS_ALLOCATED;
873 pModule->dgroup_entry = pModule->dgroup ? pModule->seg_table +
874 (pModule->dgroup - 1) * sizeof(SEGTABLEENTRY) : 0;
879 /**********************************************************************
880 * IsSharedSelector (KERNEL.345)
882 BOOL16 WINAPI IsSharedSelector16( HANDLE16 selector )
884 /* Check whether the selector belongs to a DLL */
885 NE_MODULE *pModule = NE_GetPtr( selector );
886 if (!pModule) return FALSE;
887 return (pModule->flags & NE_FFLAGS_LIBMODULE) != 0;