source: trunk/src/kernel32/windllbase.cpp@ 3059

Last change on this file since 3059 was 3059, checked in by sandervl, 25 years ago

Dll dependency changes

File size: 21.5 KB
Line 
1/* $Id: windllbase.cpp,v 1.11 2000-03-09 19:03:20 sandervl Exp $ */
2
3/*
4 * Win32 Dll base class
5 *
6 * Copyright 1998-1999 Sander van Leeuwen (sandervl@xs4all.nl)
7 *
8 * Unloading of a dll always happens in order of dependency (taking nr of
9 * loads into account)
10 * Unloading of dynamically loaded dll (with LoadLibrary) in deleteAll
11 * is done in LIFO order (NT exhibits the same behaviour)
12 *
13 * RemoveCircularDependency: TODO: Send process detach message here??
14 *
15 * Project Odin Software License can be found in LICENSE.TXT
16 *
17 */
18#define INCL_DOSFILEMGR /* File Manager values */
19#define INCL_DOSERRORS /* DOS Error values */
20#define INCL_DOSPROCESS /* DOS Process values */
21#define INCL_DOSMODULEMGR
22#define INCL_DOSMISC /* DOS Miscellanous values */
23#define INCL_WIN
24#include <os2wrap.h> //Odin32 OS/2 api wrappers
25#include <stdio.h>
26#include <string.h>
27#include <stdlib.h>
28#include <iostream.h>
29#include <fstream.h>
30#include <misc.h>
31#include <win32api.h>
32#include <pefile.h>
33#include <windllbase.h>
34#include <wprocess.h>
35#include "exceptions.h"
36#include "exceptutil.h"
37#include "cio.h"
38#include "vmutex.h"
39#include "oslibmisc.h"
40#include "oslibdos.h"
41#include "profile.h"
42
43#define DBG_LOCALLOG DBG_windllbase
44#include "dbglocal.h"
45
46VMutex dlllistmutex; //protects linked lists of heaps
47
48//******************************************************************************
49//******************************************************************************
50Win32DllBase::Win32DllBase(HINSTANCE hinstance, WIN32DLLENTRY DllEntryPoint,
51 Win32ImageBase *parent)
52 : Win32ImageBase(hinstance),
53 referenced(0), fSkipEntryCalls(FALSE), next(NULL), fInserted(FALSE),
54 fAttachedToProcess(FALSE), fUnloaded(FALSE),
55 nrDynamicLibRef(0), fLoadLibrary(FALSE), fDisableUnload(FALSE)
56{
57 dllEntryPoint = DllEntryPoint;
58
59 setUnloadOrder(parent);
60
61 dprintf(("Win32DllBase::Win32DllBase %x %s", hinstance, szModule));
62}
63//******************************************************************************
64//******************************************************************************
65Win32DllBase::~Win32DllBase()
66{
67 dprintf(("Win32DllBase::~Win32DllBase %s", szModule));
68
69 if(errorState == NO_ERROR && !fUnloaded)
70 {
71 detachProcess();
72 }
73
74 dlllistmutex.enter();
75 if(head == this) {
76 head = next;
77 }
78 else {
79 Win32DllBase *dll = head;
80 while(dll && dll->next != this) {
81 dll = dll->next;
82 }
83 if(dll == NULL) {
84 dprintf(("~Win32DllBase: Can't find dll!\n"));
85 dlllistmutex.leave();
86 return;
87 }
88 dll->next = next;
89 }
90 dlllistmutex.leave();
91}
92//******************************************************************************
93//******************************************************************************
94void Win32DllBase::loadLibrary()
95{
96 //dummy
97}
98//******************************************************************************
99//******************************************************************************
100void Win32DllBase::incDynamicLib()
101{
102 if(nrDynamicLibRef == 0) {
103 dlllistmutex.enter();
104 loadLibDlls.Push((ULONG)this);
105 dlllistmutex.leave();
106 }
107 nrDynamicLibRef++;
108}
109//******************************************************************************
110//******************************************************************************
111void Win32DllBase::decDynamicLib()
112{
113 nrDynamicLibRef--;
114 if(nrDynamicLibRef == 0) {
115 dlllistmutex.enter();
116 loadLibDlls.Remove((ULONG)this);
117 dlllistmutex.leave();
118 }
119}
120//******************************************************************************
121//unload of dlls needs to be done in reverse order of dependencies
122//Note: Only necessary for pe loader; the OS/2 loader takes care of this
123//for win32k/pe2lx
124//******************************************************************************
125void Win32DllBase::setUnloadOrder(Win32ImageBase *parent)
126{
127 Win32DllBase *dll;
128 Win32DllBase *parentdll = NULL;
129
130 dlllistmutex.enter();
131 if(parent) {
132 dll = head;
133 while(dll) {
134 if(dll->getInstanceHandle() == parent->getInstanceHandle()) {
135 parentdll = dll;
136 break;
137 }
138 dll = dll->next;
139 }
140 }
141
142 //first check if this dll is already at a lower position (further down the list)
143 //than the parent
144 if(parentdll && fInserted) {//already in the list?
145 dll = parentdll->next;
146 while(dll) {
147 if(dll->getInstanceHandle() == getInstanceHandle()) {
148 dlllistmutex.leave();
149 return; //it's at a lower position, so no need to change anything
150 }
151 dll = dll->next;
152 }
153
154 //it's already in the list but not at the right position; remove it now
155 if(head == this) {
156 head = next;
157 }
158 else {
159 dll = head;
160 while(dll->next) {
161 if(dll->next == this) {
162 dll->next = next;
163 break;
164 }
165 dll = dll->next;
166 }
167 }
168 }
169 else
170 if(fInserted) {//already in the list?
171 dlllistmutex.leave();
172 return;
173 }
174 //(re)insert it in the list after it's parent
175 if(parentdll) {
176 next = parentdll->next;
177 parentdll->next = this;
178 }
179 else {//no parent or exe, just add it at the start of the list
180 next = head;
181 head = this;
182 }
183 fInserted = TRUE;
184
185 //Now do the same thing for the child dependencies
186 QueueItem *item;
187
188 item = loadedDlls.Head();
189 while(item) {
190 dll = (Win32DllBase *)loadedDlls.getItem(item);
191 //Check for circular dependencies (i.e. in Lotus Notes)
192 if(dll != parentdll) {
193 dll->setUnloadOrder(this);
194 }
195
196 item = loadedDlls.getNext(item);
197 }
198
199 dlllistmutex.leave();
200}
201//******************************************************************************
202//******************************************************************************
203#ifdef DEBUG
204ULONG Win32DllBase::AddRef(char *parentname)
205#else
206ULONG Win32DllBase::AddRef()
207#endif
208{
209 Win32DllBase *dll;
210
211 dprintf(("Win32DllBase::AddRef %s->%s %d", parentname, getModuleName(), referenced+1));
212 ++referenced;
213#ifdef DEBUG
214 if(referenced == 1) {
215#ifdef DEBUG_ENABLELOG_LEVEL2
216 printListOfDlls();
217#endif
218 //printDependencies(NULL);
219 }
220#endif
221
222 return referenced;
223}
224//******************************************************************************
225//******************************************************************************
226ULONG Win32DllBase::Release()
227{
228 Queue queue;
229 QueueItem *item;
230 Win32DllBase *dll;
231 LONG ret;
232
233 dprintf(("Win32DllBase::Release %s %d", getModuleName(), referenced-1));
234
235 ret = --referenced;
236 if(ret <= 0) {
237 //make copy of linked list of dependencies
238 queue = loadedDlls;
239
240 //remove any circular dependencies on this dll that might be present
241 item = queue.Head();
242 while(item) {
243 dll = (Win32DllBase *)queue.getItem(item);
244 if(dll == NULL) {
245 dprintf(("ERROR: Win32DllBase::Release: dll item == NULL!!"));
246 DebugInt3();
247 return -1;
248 }
249 dll->RemoveCircularDependency(this);
250 item = queue.getNext(item);
251 }
252#ifdef DEBUG
253 //printDependencies(NULL);
254#endif
255 dprintf(("Win32DllBase::Release %s referenced == 0", getModuleName()));
256
257 //delete dll object
258 delete this;
259
260 //unreference all of it's dependencies
261 item = queue.Head();
262 while(item) {
263 dll = (Win32DllBase *)queue.getItem(item);
264 if(dll == NULL) {
265 dprintf(("ERROR: Win32DllBase::Release: dll item == NULL!!"));
266 DebugInt3();
267 return -1;
268 }
269 dll->Release();
270 item = queue.getNext(item);
271 }
272 }
273 return(ret);
274}
275//******************************************************************************
276//Lotus Notes has several ugly circular dependencies in it's dlls.
277//Remove them before they cause problems.
278//******************************************************************************
279BOOL Win32DllBase::RemoveCircularDependency(Win32DllBase *parent)
280{
281 QueueItem *item, *tmp;
282 Win32DllBase *dll;
283 BOOL ret = FALSE;
284
285 //remove any circular dependencies on this dll that might be present
286 item = loadedDlls.Head();
287 while(item) {
288 dll = (Win32DllBase *)loadedDlls.getItem(item);
289 if(dll == NULL) {
290 dprintf(("ERROR: Win32DllBase::Release: dll item == NULL!!"));
291 DebugInt3();
292 return FALSE;
293 }
294 tmp = loadedDlls.getNext(item);
295 if(dll == parent) {
296 dprintf(("Removing CIRCULAR dependency %s->%s", parent->getModuleName(), dll->getModuleName()));
297 loadedDlls.Remove(item);
298 ret = TRUE;
299 }
300//// else ret |= dll->RemoveCircularDependency(parent);
301 item = tmp;
302 }
303 //TODO: Send process detach message here??
304 return ret;
305}
306//******************************************************************************
307//There's a slight problem with our dependency procedure.
308//example: gdi32 is loaded -> depends on kernel32 (which is already loaded)
309// kernel32's reference count isn't updated
310// (when we load gdi32, we don't know which dlls it depends on and which
311// of those are already loaded and which aren't)
312//-> solution: Determine reference counts of dependant lx dlls and update those
313// reference counts
314//******************************************************************************
315void Win32DllBase::updateDependencies()
316{
317 QueueItem *item;
318 Win32DllBase *dll, *depdll;
319 ULONG refcount;
320
321 dlllistmutex.enter();
322 item = loadedDlls.Head();
323 while(item) {
324 depdll = (Win32DllBase *)loadedDlls.getItem(item);
325 if(depdll == NULL) {
326 dprintf(("updateDependencies: depdll == NULL!!"));
327 DebugInt3();
328 return;
329 }
330 refcount = 0;
331 dll = head;
332
333 while(dll) {
334 if(dll->dependsOn(depdll)) {
335 refcount++;
336 }
337 dll = dll->getNext();
338 }
339 if(refcount > depdll->referenced) {
340 dprintf(("Win32DllBase::updateDependencies changing refcount of %s to %d (old=%d)", depdll->getModuleName(), refcount, depdll->referenced));
341 depdll->referenced = refcount;
342 }
343
344 item = loadedDlls.getNext(item);
345 }
346 dlllistmutex.leave();
347}
348//******************************************************************************
349//******************************************************************************
350#ifdef DEBUG
351void Win32DllBase::printDependencies(char *parent)
352{
353 QueueItem *item;
354 Win32DllBase *dll;
355 ULONG ret;
356
357 dprintf(("Dependency list: %s->%s %d", parent, getModuleName(), referenced));
358 item = loadedDlls.Head();
359 while(item) {
360 dll = (Win32DllBase *)loadedDlls.getItem(item);
361 if(dll == NULL) {
362 return;
363 }
364 dll->printDependencies(getModuleName());
365 item = loadedDlls.getNext(item);
366 }
367}
368//******************************************************************************
369//******************************************************************************
370#ifdef DEBUG_ENABLELOG_LEVEL2
371void Win32DllBase::printListOfDlls()
372{
373 Win32DllBase *dll;
374
375 dll = head;
376
377 dprintf2(("Win32DllBase::Win32DllBase: List of loaded dlls:"));
378 while(dll) {
379 dprintf2(("DLL %s %d", dll->szModule, dll->referenced));
380 dll = dll->next;
381 }
382}
383#endif
384#endif
385//******************************************************************************
386//******************************************************************************
387BOOL Win32DllBase::attachProcess()
388{
389 WINEXCEPTION_FRAME exceptFrame;
390 USHORT sel;
391 THDB *thdb;
392 BOOL rc, fSetExceptionHandler;
393
394 if(fAttachedToProcess)
395 return TRUE;
396
397 fAttachedToProcess = TRUE;
398
399 thdb = GetThreadTHDB();
400 fSetExceptionHandler = (!thdb || thdb->teb_sel != GetFS());
401
402 //Note: The Win32 exception structure references by FS:[0] is the same
403 // in OS/2
404 if(fSetExceptionHandler) {
405 OS2SetExceptionHandler((void *)&exceptFrame);
406 sel = SetWin32TIB();
407 }
408
409 //Allocate TLS index for this module
410 tlsAlloc();
411 tlsAttachThread(); //setup TLS (main thread)
412
413 if(fSkipEntryCalls || dllEntryPoint == NULL) {
414 dprintf(("attachProcess not required for dll %s", szModule));
415 if(fSetExceptionHandler) {
416 SetFS(sel);
417 OS2UnsetExceptionHandler((void *)&exceptFrame);
418 }
419 return(TRUE);
420 }
421
422 dprintf(("attachProcess to dll %s", szModule));
423
424 rc = dllEntryPoint(hinstance, DLL_PROCESS_ATTACH, 0);
425
426 dprintf(("attachProcess to dll %s DONE", szModule));
427
428 if(fSetExceptionHandler) {
429 SetFS(sel);
430 OS2UnsetExceptionHandler((void *)&exceptFrame);
431 }
432 return rc;
433}
434//******************************************************************************
435//******************************************************************************
436BOOL Win32DllBase::detachProcess()
437{
438 WINEXCEPTION_FRAME exceptFrame;
439 USHORT sel;
440 BOOL rc;
441
442 if(fSkipEntryCalls || dllEntryPoint == NULL) {
443 tlsDetachThread(); //destroy TLS (main thread)
444 fUnloaded = TRUE;
445 return(TRUE);
446 }
447
448 dprintf(("detachProcess from dll %s", szModule));
449
450 //Note: The Win32 exception structure references by FS:[0] is the same
451 // in OS/2
452 OS2SetExceptionHandler((void *)&exceptFrame);
453
454 fUnloaded = TRUE;
455 sel = SetWin32TIB();
456 rc = dllEntryPoint(hinstance, DLL_PROCESS_DETACH, 0);
457 SetFS(sel);
458 tlsDetachThread(); //destroy TLS (main thread)
459 tlsDelete();
460
461 OS2UnsetExceptionHandler((void *)&exceptFrame);
462
463 return rc;
464}
465//******************************************************************************
466//******************************************************************************
467BOOL Win32DllBase::attachThread()
468{
469 WINEXCEPTION_FRAME exceptFrame;
470 BOOL rc;
471
472 if(fSkipEntryCalls || dllEntryPoint == NULL)
473 return(TRUE);
474
475 dprintf(("attachThread to dll %s", szModule));
476
477 rc = dllEntryPoint(hinstance, DLL_THREAD_ATTACH, 0);
478
479 dprintf(("attachThread to dll %s DONE", szModule));
480
481 return rc;
482}
483//******************************************************************************
484//******************************************************************************
485BOOL Win32DllBase::detachThread()
486{
487 WINEXCEPTION_FRAME exceptFrame;
488 BOOL rc;
489
490 if(fSkipEntryCalls || dllEntryPoint == NULL)
491 return(TRUE);
492
493 dprintf(("detachThread from dll %s", szModule));
494
495 rc = dllEntryPoint(hinstance, DLL_THREAD_DETACH, 0);
496 return rc;
497}
498//******************************************************************************
499//Send DLL_THREAD_ATTACH message to all dlls for a new thread
500//******************************************************************************
501void Win32DllBase::attachThreadToAllDlls()
502{
503 dlllistmutex.enter();
504 Win32DllBase *dll = Win32DllBase::head;
505 while(dll) {
506 dll->attachThread();
507 dll = dll->getNext();
508 }
509 dlllistmutex.leave();
510}
511//******************************************************************************
512//Send DLL_THREAD_DETACH message to all dlls for thread that's about to die
513//******************************************************************************
514void Win32DllBase::detachThreadFromAllDlls()
515{
516 dlllistmutex.enter();
517 Win32DllBase *dll = Win32DllBase::head;
518 while(dll) {
519 dll->detachThread();
520 dll = dll->getNext();
521 }
522 dlllistmutex.leave();
523}
524//******************************************************************************
525//Setup TLS structure for all dlls for a new thread
526//******************************************************************************
527void Win32DllBase::tlsAttachThreadToAllDlls()
528{
529 dlllistmutex.enter();
530 Win32DllBase *dll = Win32DllBase::head;
531 while(dll) {
532 dll->tlsAttachThread();
533 dll = dll->getNext();
534 }
535 dlllistmutex.leave();
536}
537//******************************************************************************
538//Destroy TLS structure for all dlls for a thread that's about to die
539//******************************************************************************
540void Win32DllBase::tlsDetachThreadFromAllDlls()
541{
542 dlllistmutex.enter();
543 Win32DllBase *dll = Win32DllBase::head;
544 while(dll) {
545 dll->tlsDetachThread();
546 dll = dll->getNext();
547 }
548 dlllistmutex.leave();
549}
550//******************************************************************************
551//******************************************************************************
552void Win32DllBase::deleteAll()
553{
554 Win32DllBase *dll = Win32DllBase::head;
555
556 dprintf(("Win32DllBase::deleteAll"));
557
558#ifdef DEBUG_ENABLELOG_LEVEL2
559 if(dll) dll->printListOfDlls();
560#endif
561
562 dlllistmutex.enter();
563 while(dll) {
564 dll->Release();
565 dll = Win32DllBase::head;
566 }
567 dlllistmutex.leave();
568 dprintf(("Win32DllBase::deleteAll Done!"));
569}
570//******************************************************************************
571//Delete dlls loaded by LoadLibrary(Ex) in LIFO order
572//******************************************************************************
573void Win32DllBase::deleteDynamicLibs()
574{
575 Win32DllBase *dll = head;
576 QueueItem *item;
577
578 dprintf(("Win32DllBase::deleteDynamicLibs"));
579#ifdef DEBUG_ENABLELOG_LEVEL2
580 if(dll) dll->printListOfDlls();
581#endif
582
583 dlllistmutex.enter();
584
585 item = loadLibDlls.Head();
586 while(item) {
587 dll = (Win32DllBase *)loadLibDlls.getItem(item);
588 int dynref = dll->nrDynamicLibRef;
589 if(dynref) {
590 while(dynref) {
591 dynref--;
592 dll->decDynamicLib();
593 dll->Release();
594 }
595 }
596 else DebugInt3();
597 item = loadLibDlls.Head(); //queue could have been changed, so start from the beginning
598 }
599
600 dlllistmutex.leave();
601}
602//******************************************************************************
603//******************************************************************************
604Win32DllBase *Win32DllBase::getFirst()
605{
606 return head;
607}
608//******************************************************************************
609//Add renaming profile strings for ole32 & netapi32 to odin.ini if they aren't
610//already there
611//******************************************************************************
612void Win32DllBase::setDefaultRenaming()
613{
614 char renameddll[CCHMAXPATH];
615
616 if(ODIN_PROFILE_GetOdinIniString(DLLRENAMEWIN_SECTION, "OLE32", "", renameddll,
617 sizeof(renameddll)-1) <= 1)
618 {
619 ODIN_PROFILE_SetOdinIniString(DLLRENAMEWIN_SECTION, "OLE32", "OLE32OS2");
620 ODIN_PROFILE_SetOdinIniString(DLLRENAMEOS2_SECTION, "OLE32OS2", "OLE32");
621 }
622 if(ODIN_PROFILE_GetOdinIniString(DLLRENAMEWIN_SECTION, "OLEAUT32", "", renameddll,
623 sizeof(renameddll)-1) <= 1)
624 {
625 ODIN_PROFILE_SetOdinIniString(DLLRENAMEWIN_SECTION, "OLEAUT32", "OLAUTOS2");
626 ODIN_PROFILE_SetOdinIniString(DLLRENAMEOS2_SECTION, "OLAUTOS2", "OLEAUT32");
627 }
628 if(ODIN_PROFILE_GetOdinIniString(DLLRENAMEWIN_SECTION, "NETAPI32", "", renameddll,
629 sizeof(renameddll)-1) <= 1)
630 {
631 ODIN_PROFILE_SetOdinIniString(DLLRENAMEWIN_SECTION, "NETAPI32", "WNETAP32");
632 ODIN_PROFILE_SetOdinIniString(DLLRENAMEOS2_SECTION, "WNETAP32", "NETAPI32");
633 }
634}
635//******************************************************************************
636//rename dll if necessary:
637// Win32 to OS/2 : (i.e. OLE32 -> OLE32OS2)
638// or
639// OS/2 to Win32 : (i.e. OLE32OS2 -> OLE32)
640//******************************************************************************
641void Win32DllBase::renameDll(char *dllname, BOOL fWinToOS2)
642{
643 char modname[CCHMAXPATH];
644 char renameddll[CCHMAXPATH];
645 char *namestart;
646 char *sectionname;
647
648 if(fWinToOS2) {
649 sectionname = DLLRENAMEWIN_SECTION;
650 }
651 else {
652 sectionname = DLLRENAMEOS2_SECTION;
653 }
654 namestart = OSLibStripPath(dllname);
655 strcpy(modname, namestart);
656 char *dot = strrchr(modname, '.');
657 if(dot)
658 *dot = 0;
659 strupr(modname);
660 if(ODIN_PROFILE_GetOdinIniString(sectionname, modname, "", renameddll,
661 sizeof(renameddll)-1) > 1)
662 {
663 if(namestart == dllname) {
664 strcpy(dllname, renameddll);
665 }
666 else {
667 *namestart = 0;
668 strcat(dllname, renameddll);
669 }
670 strcat(dllname, ".dll");
671 }
672 return;
673}
674//******************************************************************************
675//******************************************************************************
676Win32DllBase *Win32DllBase::findModule(char *dllname, BOOL fRenameFirst)
677{
678 Win32DllBase *dll;
679 char szDllName[CCHMAXPATH];
680 char *dot, *temp;
681
682//// dprintf2(("findModule %s", dllname));
683
684 strcpy(szDllName, OSLibStripPath(dllname));
685 strupr(szDllName);
686
687 if(fRenameFirst) {
688 renameDll(szDllName, FALSE);
689 }
690
691 dot = strstr(szDllName, ".");
692 if(dot)
693 *dot = 0;
694
695 dlllistmutex.enter();
696 dll = head;
697 while(dll) {
698 if(strcmpi(szDllName, dll->szModule) == 0) {
699 dlllistmutex.leave();
700 return(dll);
701 }
702
703 dll = dll->next;
704 }
705 dlllistmutex.leave();
706 return(NULL);
707}
708//******************************************************************************
709//******************************************************************************
710Win32DllBase *Win32DllBase::findModule(WIN32DLLENTRY DllEntryPoint)
711{
712 dprintf2(("findModule %X", DllEntryPoint));
713
714 dlllistmutex.enter();
715 Win32DllBase *mod = Win32DllBase::head;
716 while(mod != NULL) {
717 dbgCheckObj(mod);
718 if(mod->dllEntryPoint == DllEntryPoint) {
719 dlllistmutex.leave();
720 return(mod);
721 }
722 mod = mod->next;
723 }
724 dlllistmutex.leave();
725 return(NULL);
726}
727//******************************************************************************
728//******************************************************************************
729Win32DllBase *Win32DllBase::findModule(HINSTANCE hinstance)
730{
731 dlllistmutex.enter();
732
733 Win32DllBase *mod = Win32DllBase::head;
734 while(mod != NULL) {
735 dbgCheckObj(mod);
736 if(mod->hinstance == hinstance) {
737 dlllistmutex.leave();
738 return(mod);
739 }
740 mod = mod->next;
741 }
742 dlllistmutex.leave();
743 return(NULL);
744}
745//******************************************************************************
746//******************************************************************************
747BOOL Win32DllBase::isDll()
748{
749 return TRUE;
750}
751//******************************************************************************
752//******************************************************************************
753void Win32DllBase::setThreadLibraryCalls(BOOL fEnable)
754{
755 // if fEnable == true, do call the ATTACH_THREAD, DETACH_THREAD functions
756 // if fEnable == false, do not call the ATTACH_THREAD, DETACH_THREAD functions
757 fSkipEntryCalls = !fEnable;
758}
759
760//******************************************************************************
761//******************************************************************************
762Win32DllBase *Win32DllBase::head = NULL;
763Queue Win32DllBase::loadLibDlls;
Note: See TracBrowser for help on using the repository browser.