source: trunk/src/kernel32/windll.cpp@ 651

Last change on this file since 651 was 651, checked in by sandervl, 26 years ago

Dll load order bugfix

File size: 15.3 KB
Line 
1/* $Id: windll.cpp,v 1.14 1999-08-23 17:02:35 sandervl Exp $ */
2
3/*
4 * Win32 DLL class
5 *
6 * Copyright 1998 Sander van Leeuwen (sandervl@xs4all.nl)
7 *
8 *
9 * Project Odin Software License can be found in LICENSE.TXT
10 *
11 */
12#define INCL_DOSFILEMGR /* File Manager values */
13#define INCL_DOSERRORS /* DOS Error values */
14#define INCL_DOSPROCESS /* DOS Process values */
15#define INCL_DOSMODULEMGR
16#define INCL_DOSMISC /* DOS Miscellanous values */
17#define INCL_WIN
18#include <os2wrap.h> //Odin32 OS/2 api wrappers
19#include <stdio.h>
20#include <string.h>
21#include <stdlib.h>
22#include <iostream.h>
23#include <fstream.h>
24#include <misc.h>
25#include <nameid.h>
26#include <win32type.h>
27#include <pefile.h>
28#include <windll.h>
29#include <wprocess.h>
30#include "exceptions.h"
31#include "exceptutil.h"
32#include "cio.h"
33#include "vmutex.h"
34
35VMutex dlllistmutex; //protects linked lists of heaps
36
37/***********************************
38 * PH: fixups for missing os2win.h *
39 ***********************************/
40
41void _System SetLastError(ULONG ulError);
42
43//******************************************************************************
44//******************************************************************************
45Win32Dll::Win32Dll(char *szDllName, Win32Image *parentImage)
46 : Win32Image(szDllName), referenced(0),
47 fSkipEntryCalls(FALSE), fSystemDll(FALSE),
48 fAttachedToProcess(FALSE)
49{
50 fSystemDll = isSystemDll(szFileName);
51 fUnloaded = FALSE;
52
53 dlllistmutex.enter();
54 if(head == NULL || parentImage == NULL || parentImage->isDll() == FALSE) { //does the head dll depend on this one?
55 next = head;
56 head = this;
57 }
58 else {
59 //If we have a parent, we must make sure it is deleted before we are!
60 //(inserted after the parent)
61 if(head == parentImage) {
62 next = head->next;
63 head->next = this;
64 }
65 else {
66 Win32Dll *cur = head;
67 while(cur) {
68 if(cur == parentImage) {
69 break;
70 }
71 cur = cur->next;
72 }
73 next = cur->next;
74 cur->next = this;
75 }
76 }
77 dlllistmutex.leave();
78
79 dllEntryPoint = 0;
80
81 dprintf(("Win32Dll::Win32Dll %s %s loaded by %s", szFileName, szModule,
82 (parentImage) ? parentImage->getModuleName() : "Unknown"));
83}
84//******************************************************************************
85//******************************************************************************
86Win32Dll::Win32Dll(HINSTANCE hinstance, int NameTableId, int Win32TableId,
87 WIN32DLLENTRY DllEntryPoint) :
88 Win32Image(hinstance, NameTableId, Win32TableId),
89 referenced(0), fSkipEntryCalls(FALSE), fSystemDll(FALSE),
90 fAttachedToProcess(FALSE)
91{
92 dllEntryPoint = DllEntryPoint;
93 fUnloaded = FALSE;
94
95 dlllistmutex.enter();
96 next = head;
97 head = this;
98 dlllistmutex.leave();
99
100 dprintf(("Win32Dll::Win32Dll %s", szModule));
101}
102//******************************************************************************
103//******************************************************************************
104void Win32Dll::OS2DllInit(HINSTANCE hinstance, int NameTableId, int Win32TableId,
105 WIN32DLLENTRY DllEntryPoint)
106{
107 dllEntryPoint = DllEntryPoint;
108 fUnloaded = FALSE;
109
110 Win32Image::OS2ImageInit(hinstance, NameTableId, Win32TableId);
111}
112//******************************************************************************
113//******************************************************************************
114Win32Dll::~Win32Dll()
115{
116 Win32Dll *dll = head;
117
118 dprintf(("Win32Dll::~Win32Dll %s", szModule));
119
120 //first remove it from the linked list so converted win32 dlls won't
121 //be deleted twice (as DosFreeModule results in a call to DllExitList (wprocess.cpp)
122 dlllistmutex.enter();
123 if(head == this) {
124 head = next;
125 }
126 else {
127 while(dll && dll->next != this) {
128 dll = dll->next;
129 }
130 if(dll == NULL) {
131 dprintf(("~Win32Dll: Can't find dll!\n"));
132 dlllistmutex.leave();
133 return;
134 }
135 dll->next = next;
136 }
137 dlllistmutex.leave();
138 if(errorState == NO_ERROR && !fUnloaded)
139 {
140 detachProcess();
141 }
142}
143//******************************************************************************
144//ASSUMPTION: called by FreeLibrary
145//******************************************************************************
146ULONG Win32Dll::Release()
147{
148 ULONG ret = --referenced;
149
150 if(ret == 0) {
151 dprintf(("Win32Dll::Release, referenced == 0\n"));
152 if(fSystemDll) {
153 DosFreeModule((HMODULE)hinstance);
154 fUnloaded = TRUE;
155 }
156 delete this;
157 }
158 return(ret);
159}
160//******************************************************************************
161//******************************************************************************
162BOOL Win32Dll::init(ULONG reservedMem)
163{
164 char modname[CCHMAXPATH];
165 char *syspath;
166 FILE *dllfile;
167 APIRET rc;
168 BOOL fRet;
169
170 if(fSystemDll == FALSE && fNativePEImage == TRUE)
171 {//might be win32 dll, so check this
172 strupr(szFileName);
173 if(!strstr(szFileName, ".DLL")) {
174 strcat(szFileName,".DLL");
175 }
176 dllfile = fopen(szFileName, "r");
177 if(dllfile == NULL) {//search in libpath for dll
178 syspath = getenv("WIN32LIBPATH");
179 if(syspath) {
180 strcpy(modname, syspath);
181 if(modname[strlen(modname)-1] != '\\') {
182 strcat(modname, "\\");
183 }
184 strcat(modname, szFileName);
185 strcpy(szFileName, modname);
186 }
187 }
188 else fclose(dllfile);
189 if(isPEImage(szFileName) == TRUE) {
190 fRet = Win32Image::init(0);
191 dllEntryPoint = (WIN32DLLENTRY)entryPoint;
192 return fRet;
193 }
194 //converted win32 dll
195 fNativePEImage = FALSE;
196 }
197 //else load system dlls using DosLoadModule
198 char szModuleFailure[CCHMAXPATH] = "";
199
200 rc = DosLoadModule(szModuleFailure, sizeof(szModuleFailure), szFileName, (HMODULE *)&hinstance);
201 if(rc) {
202 dprintf(("DosLoadModule returned %X for %s\n", rc, szModuleFailure));
203 errorState = rc;
204 return(FALSE);
205 }
206 return(TRUE);
207}
208//******************************************************************************
209char *sysmodules[] = {"KERNEL32", "USER32", "GDI32", "WINMM", "DSOUND", "DDRAW",
210 "WNETAP32", "MPR", "OLE32", "ADVAPI32", "COMDLG32",
211 "WINSPOOL", "SHELL32", "TAPI32", "CAPI32", "VERSION",
212 "WSOCK32", "COMCTL32", "NTDLL"};
213//******************************************************************************
214BOOL Win32Dll::isSystemDll(char *szFileName)
215{
216 int i;
217 char *dot;
218 char szModule[CCHMAXPATH];
219
220 strcpy(szModule, szFileName);
221 strupr(szModule);
222 dot = strstr(szModule, ".");
223 if(dot)
224 *dot = 0;
225
226 for(i=0;i<sizeof(sysmodules)/sizeof(char *);i++) {
227 if(!strcmp(szModule, sysmodules[i]))
228 return(TRUE);
229 }
230 return(FALSE);
231}
232//******************************************************************************
233//Could be more efficient, but I bet this is faster than the OS/2 loader!
234//******************************************************************************
235ULONG Win32Dll::getApi(char *name)
236{
237 APIRET rc;
238 ULONG apiaddr, i, apilen;
239 char *apiname;
240 char tmp[4];
241 NameExport *curexport;
242 ULONG ulAPIOrdinal; /* api requested by ordinal */
243
244 apilen = strlen(name) + 1;
245 if(apilen < 4)
246 {
247 *(ULONG *)tmp = 0;
248 strcpy(tmp, name);
249 apiname = tmp;
250 }
251 else apiname = name;
252
253 curexport = nameexports;
254 for(i=0;
255 i<nrNameExports;
256 i++)
257 {
258 if(apilen == curexport->nlength &&
259 *(ULONG *)curexport->name == *(ULONG *)name)
260 {
261 if(strcmp(curexport->name, name) == 0)
262 return(curexport->virtaddr);
263 }
264 curexport = (NameExport *)((ULONG)curexport->name + curexport->nlength);
265 }
266
267 if(fSystemDll || !fNativePEImage)
268 {
269 rc = DosQueryProcAddr(hinstance, 0, name, (PFN *)&apiaddr);
270 if(rc)
271 {
272 SetLastError(rc); /* raise error condition */
273 return(0);
274 }
275
276 //Add to lookup table, so we don't have to call DosQueryProcAddr
277 //multiple times for the same api (when imported by other dlls)
278 AddNameExport(apiaddr, name, 0);
279 return(apiaddr);
280 }
281 return(0);
282}
283//******************************************************************************
284//******************************************************************************
285ULONG Win32Dll::getApi(int ordinal)
286{
287 APIRET rc;
288 ULONG apiaddr, i;
289 OrdExport *curexport;
290 NameExport *nexport;
291
292 if(fSystemDll || !fNativePEImage) {
293 rc = DosQueryProcAddr(hinstance, ordinal, NULL, (PFN *)&apiaddr);
294 if(rc) return(0);
295 else return(apiaddr);
296 }
297 curexport = ordexports;
298 for(i=0;i<nrOrdExports;i++) {
299 if(curexport->ordinal == ordinal)
300 return(curexport->virtaddr);
301 curexport++;
302 }
303 //Name exports also contain an ordinal, so check this
304 nexport = nameexports;
305 for(i=0;i<nrNameExports;i++) {
306 if(nexport->ordinal == ordinal)
307 return(nexport->virtaddr);
308 nexport = (NameExport *)((ULONG)nexport->name + nexport->nlength);
309 }
310 return(0);
311}
312//******************************************************************************
313//******************************************************************************
314BOOL Win32Dll::attachProcess()
315{
316 WINEXCEPTION_FRAME exceptFrame;
317 USHORT sel;
318 BOOL rc;
319
320 if(fAttachedToProcess)
321 return TRUE;
322
323 fAttachedToProcess = TRUE;
324
325 //Allocate TLS index for this module
326 tlsAlloc();
327 tlsAttachThread(); //setup TLS (main thread)
328
329 if(fSystemDll || fSkipEntryCalls || dllEntryPoint == NULL) {
330 dprintf(("attachProcess not required for dll %s", szModule));
331 return(TRUE);
332 }
333
334 dprintf(("attachProcess to dll %s", szModule));
335
336 //Note: The Win32 exception structure references by FS:[0] is the same
337 // in OS/2
338 OS2SetExceptionHandler((void *)&exceptFrame);
339
340 sel = SetWin32TIB();
341 rc = dllEntryPoint(hinstance, DLL_PROCESS_ATTACH, 0);
342 SetFS(sel);
343
344 OS2UnsetExceptionHandler((void *)&exceptFrame);
345
346 return rc;
347}
348//******************************************************************************
349//******************************************************************************
350BOOL Win32Dll::detachProcess()
351{
352 WINEXCEPTION_FRAME exceptFrame;
353 USHORT sel;
354 BOOL rc;
355
356 if(fSystemDll || fSkipEntryCalls || dllEntryPoint == NULL) {
357 tlsDetachThread(); //destroy TLS (main thread)
358 return(TRUE);
359 }
360
361 dprintf(("detachProcess from dll %s", szModule));
362
363 //Note: The Win32 exception structure references by FS:[0] is the same
364 // in OS/2
365 OS2SetExceptionHandler((void *)&exceptFrame);
366
367 fUnloaded = TRUE;
368 sel = SetWin32TIB();
369 rc = dllEntryPoint(hinstance, DLL_PROCESS_DETACH, 0);
370 SetFS(sel);
371 tlsDetachThread(); //destroy TLS (main thread)
372 tlsDelete();
373
374 OS2UnsetExceptionHandler((void *)&exceptFrame);
375
376 return rc;
377}
378//******************************************************************************
379//******************************************************************************
380BOOL Win32Dll::attachThread()
381{
382 WINEXCEPTION_FRAME exceptFrame;
383 BOOL rc;
384
385 if(fSystemDll || fSkipEntryCalls || dllEntryPoint == NULL)
386 return(TRUE);
387
388 dprintf(("attachThread to dll %s", szModule));
389 //Note: The Win32 exception structure references by FS:[0] is the same
390 // in OS/2
391 OS2SetExceptionHandler((void *)&exceptFrame);
392
393 rc = dllEntryPoint(hinstance, DLL_THREAD_ATTACH, 0);
394
395 OS2UnsetExceptionHandler((void *)&exceptFrame);
396 return rc;
397}
398//******************************************************************************
399//******************************************************************************
400BOOL Win32Dll::detachThread()
401{
402 WINEXCEPTION_FRAME exceptFrame;
403 BOOL rc;
404
405 if(fSystemDll || fSkipEntryCalls || dllEntryPoint == NULL)
406 return(TRUE);
407
408 dprintf(("attachThread from dll %s", szModule));
409
410 //Note: The Win32 exception structure references by FS:[0] is the same
411 // in OS/2
412 OS2SetExceptionHandler((void *)&exceptFrame);
413
414 rc = dllEntryPoint(hinstance, DLL_THREAD_DETACH, 0);
415
416 OS2UnsetExceptionHandler((void *)&exceptFrame);
417 return rc;
418}
419//******************************************************************************
420//Send DLL_THREAD_ATTACH message to all dlls for a new thread
421//******************************************************************************
422void Win32Dll::attachThreadToAllDlls()
423{
424 Win32Dll *dll = Win32Dll::head;
425 while(dll) {
426 dll->attachThread();
427 dll = dll->getNext();
428 }
429}
430//******************************************************************************
431//Send DLL_THREAD_DETACH message to all dlls for thread that's about to die
432//******************************************************************************
433void Win32Dll::detachThreadFromAllDlls()
434{
435 Win32Dll *dll = Win32Dll::head;
436 while(dll) {
437 dll->detachThread();
438 dll = dll->getNext();
439 }
440}
441//******************************************************************************
442//Setup TLS structure for all dlls for a new thread
443//******************************************************************************
444void Win32Dll::tlsAttachThreadToAllDlls()
445{
446 Win32Dll *dll = Win32Dll::head;
447 while(dll) {
448 dll->tlsAttachThread();
449 dll = dll->getNext();
450 }
451}
452//******************************************************************************
453//Destroy TLS structure for all dlls for a thread that's about to die
454//******************************************************************************
455void Win32Dll::tlsDetachThreadFromAllDlls()
456{
457 Win32Dll *dll = Win32Dll::head;
458 while(dll) {
459 dll->tlsDetachThread();
460 dll = dll->getNext();
461 }
462}
463//******************************************************************************
464//******************************************************************************
465void Win32Dll::deleteAll()
466{
467#ifdef DEBUG
468 dlllistmutex.enter();
469 Win32Dll *dll = head;
470
471 dprintf(("Win32Dll::deleteAll: List of loaded dlls:"));
472 while(dll) {
473 dprintf(("DLL %s", dll->szModule));
474 dll = dll->next;
475 }
476 dlllistmutex.leave();
477#endif
478
479 while(Win32Dll::head) {
480 delete Win32Dll::head;
481 }
482}
483//******************************************************************************
484//******************************************************************************
485Win32Dll *Win32Dll::findModule(char *dllname)
486{
487 Win32Dll *dll;
488 char szDllName[CCHMAXPATH];
489 char *dot, *temp;
490
491 dprintf(("findModule %s", dllname));
492
493 strcpy(szDllName, StripPath(dllname));
494 strupr(szDllName);
495 dot = strstr(szDllName, ".");
496 if(dot)
497 *dot = 0;
498
499 dlllistmutex.enter();
500 dll = head;
501 while(dll) {
502 if(strcmpi(szDllName, dll->szModule) == 0) {
503 dlllistmutex.leave();
504 return(dll);
505 }
506
507 dll = dll->next;
508 }
509 dlllistmutex.leave();
510 return(NULL);
511}
512//******************************************************************************
513//******************************************************************************
514Win32Dll *Win32Dll::findModule(WIN32DLLENTRY DllEntryPoint)
515{
516 dprintf(("findModule %X", DllEntryPoint));
517
518 dlllistmutex.enter();
519 Win32Dll *mod = Win32Dll::head;
520 while(mod != NULL) {
521 dbgCheckObj(mod);
522 if(mod->dllEntryPoint == DllEntryPoint) {
523 dlllistmutex.leave();
524 return(mod);
525 }
526 mod = mod->next;
527 }
528 dlllistmutex.leave();
529 return(NULL);
530}
531//******************************************************************************
532//******************************************************************************
533Win32Dll *Win32Dll::findModule(HINSTANCE hinstance)
534{
535 dlllistmutex.enter();
536
537 Win32Dll *mod = Win32Dll::head;
538 while(mod != NULL) {
539 dbgCheckObj(mod);
540 if(mod->hinstance == hinstance) {
541 dlllistmutex.leave();
542 return(mod);
543 }
544 mod = mod->next;
545 }
546 dlllistmutex.leave();
547 return(NULL);
548}
549//******************************************************************************
550//******************************************************************************
551Win32Dll *Win32Dll::head = NULL;
Note: See TracBrowser for help on using the repository browser.