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

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

added exception stack dump code; GetLocaleInfoA fixes

File size: 22.1 KB
Line 
1/* $Id: windllbase.cpp,v 1.13 2000-05-02 20:53:14 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 else
433 if(thdb) {
434 if(thdb->teb_sel != GetFS()) {
435 dprintf(("Win32DllBase::attachProcess: FS was changed by dll entrypoint!!!!"));
436 DebugInt3();
437 }
438 }
439 return rc;
440}
441//******************************************************************************
442//******************************************************************************
443BOOL Win32DllBase::detachProcess()
444{
445 WINEXCEPTION_FRAME exceptFrame;
446 USHORT sel;
447 BOOL rc;
448
449 if(fSkipEntryCalls || dllEntryPoint == NULL) {
450 tlsDetachThread(); //destroy TLS (main thread)
451 fUnloaded = TRUE;
452 return(TRUE);
453 }
454
455 dprintf(("detachProcess from dll %s", szModule));
456
457 //Note: The Win32 exception structure references by FS:[0] is the same
458 // in OS/2
459 OS2SetExceptionHandler((void *)&exceptFrame);
460
461 fUnloaded = TRUE;
462 sel = SetWin32TIB();
463 rc = dllEntryPoint(hinstance, DLL_PROCESS_DETACH, 0);
464 SetFS(sel);
465 tlsDetachThread(); //destroy TLS (main thread)
466 tlsDelete();
467
468 OS2UnsetExceptionHandler((void *)&exceptFrame);
469
470 return rc;
471}
472//******************************************************************************
473//******************************************************************************
474BOOL Win32DllBase::attachThread()
475{
476 WINEXCEPTION_FRAME exceptFrame;
477 BOOL rc;
478
479 if(fSkipEntryCalls || dllEntryPoint == NULL)
480 return(TRUE);
481
482 dprintf(("attachThread to dll %s", szModule));
483
484 rc = dllEntryPoint(hinstance, DLL_THREAD_ATTACH, 0);
485
486 dprintf(("attachThread to dll %s DONE", szModule));
487
488 return rc;
489}
490//******************************************************************************
491//******************************************************************************
492BOOL Win32DllBase::detachThread()
493{
494 WINEXCEPTION_FRAME exceptFrame;
495 BOOL rc;
496
497 if(fSkipEntryCalls || dllEntryPoint == NULL)
498 return(TRUE);
499
500 dprintf(("detachThread from dll %s", szModule));
501
502 rc = dllEntryPoint(hinstance, DLL_THREAD_DETACH, 0);
503 return rc;
504}
505//******************************************************************************
506//Send DLL_THREAD_ATTACH message to all dlls for a new thread
507//******************************************************************************
508void Win32DllBase::attachThreadToAllDlls()
509{
510 dlllistmutex.enter();
511 Win32DllBase *dll = Win32DllBase::head;
512 while(dll) {
513 dll->attachThread();
514 dll = dll->getNext();
515 }
516 dlllistmutex.leave();
517}
518//******************************************************************************
519//Send DLL_THREAD_DETACH message to all dlls for thread that's about to die
520//******************************************************************************
521void Win32DllBase::detachThreadFromAllDlls()
522{
523 dlllistmutex.enter();
524 Win32DllBase *dll = Win32DllBase::head;
525 while(dll) {
526 dll->detachThread();
527 dll = dll->getNext();
528 }
529 dlllistmutex.leave();
530}
531//******************************************************************************
532//Setup TLS structure for all dlls for a new thread
533//******************************************************************************
534void Win32DllBase::tlsAttachThreadToAllDlls()
535{
536 dlllistmutex.enter();
537 Win32DllBase *dll = Win32DllBase::head;
538 while(dll) {
539 dll->tlsAttachThread();
540 dll = dll->getNext();
541 }
542 dlllistmutex.leave();
543}
544//******************************************************************************
545//Destroy TLS structure for all dlls for a thread that's about to die
546//******************************************************************************
547void Win32DllBase::tlsDetachThreadFromAllDlls()
548{
549 dlllistmutex.enter();
550 Win32DllBase *dll = Win32DllBase::head;
551 while(dll) {
552 dll->tlsDetachThread();
553 dll = dll->getNext();
554 }
555 dlllistmutex.leave();
556}
557//******************************************************************************
558//******************************************************************************
559void Win32DllBase::deleteAll()
560{
561 Win32DllBase *dll = Win32DllBase::head;
562
563 dprintf(("Win32DllBase::deleteAll"));
564
565#ifdef DEBUG_ENABLELOG_LEVEL2
566 if(dll) dll->printListOfDlls();
567#endif
568
569 dlllistmutex.enter();
570 while(dll) {
571 dll->Release();
572 dll = Win32DllBase::head;
573 }
574 dlllistmutex.leave();
575 dprintf(("Win32DllBase::deleteAll Done!"));
576}
577//******************************************************************************
578//Delete dlls loaded by LoadLibrary(Ex) in LIFO order
579//******************************************************************************
580void Win32DllBase::deleteDynamicLibs()
581{
582 Win32DllBase *dll = head;
583 QueueItem *item;
584
585 dprintf(("Win32DllBase::deleteDynamicLibs"));
586#ifdef DEBUG_ENABLELOG_LEVEL2
587 if(dll) dll->printListOfDlls();
588#endif
589
590 dlllistmutex.enter();
591
592 item = loadLibDlls.Head();
593 while(item) {
594 dll = (Win32DllBase *)loadLibDlls.getItem(item);
595 int dynref = dll->nrDynamicLibRef;
596 if(dynref) {
597 while(dynref) {
598 dynref--;
599 dll->decDynamicLib();
600 dll->Release();
601 }
602 }
603 else DebugInt3();
604 item = loadLibDlls.Head(); //queue could have been changed, so start from the beginning
605 }
606
607 dlllistmutex.leave();
608}
609//******************************************************************************
610//******************************************************************************
611Win32DllBase *Win32DllBase::getFirst()
612{
613 return head;
614}
615//******************************************************************************
616//Add renaming profile strings for ole32 & netapi32 to odin.ini if they aren't
617//already there
618//******************************************************************************
619void Win32DllBase::setDefaultRenaming()
620{
621 char renameddll[CCHMAXPATH];
622
623 if(ODIN_PROFILE_GetOdinIniString(DLLRENAMEWIN_SECTION, "OLE32", "", renameddll,
624 sizeof(renameddll)-1) <= 1)
625 {
626 ODIN_PROFILE_SetOdinIniString(DLLRENAMEWIN_SECTION, "OLE32", "OLE32OS2");
627 ODIN_PROFILE_SetOdinIniString(DLLRENAMEOS2_SECTION, "OLE32OS2", "OLE32");
628 }
629 if(ODIN_PROFILE_GetOdinIniString(DLLRENAMEWIN_SECTION, "OLEAUT32", "", renameddll,
630 sizeof(renameddll)-1) <= 1)
631 {
632 ODIN_PROFILE_SetOdinIniString(DLLRENAMEWIN_SECTION, "OLEAUT32", "OLAUTOS2");
633 ODIN_PROFILE_SetOdinIniString(DLLRENAMEOS2_SECTION, "OLAUTOS2", "OLEAUT32");
634 }
635 if(ODIN_PROFILE_GetOdinIniString(DLLRENAMEWIN_SECTION, "NETAPI32", "", renameddll,
636 sizeof(renameddll)-1) <= 1)
637 {
638 ODIN_PROFILE_SetOdinIniString(DLLRENAMEWIN_SECTION, "NETAPI32", "WNETAP32");
639 ODIN_PROFILE_SetOdinIniString(DLLRENAMEOS2_SECTION, "WNETAP32", "NETAPI32");
640 }
641}
642//******************************************************************************
643//rename dll if necessary:
644// Win32 to OS/2 : (i.e. OLE32 -> OLE32OS2)
645// or
646// OS/2 to Win32 : (i.e. OLE32OS2 -> OLE32)
647//******************************************************************************
648void Win32DllBase::renameDll(char *dllname, BOOL fWinToOS2)
649{
650 char modname[CCHMAXPATH];
651 char renameddll[CCHMAXPATH];
652 char *namestart;
653 char *sectionname;
654
655 if(fWinToOS2) {
656 sectionname = DLLRENAMEWIN_SECTION;
657 }
658 else {
659 sectionname = DLLRENAMEOS2_SECTION;
660 }
661 namestart = OSLibStripPath(dllname);
662 strcpy(modname, namestart);
663 char *dot = strrchr(modname, '.');
664 if(dot)
665 *dot = 0;
666 strupr(modname);
667 if(ODIN_PROFILE_GetOdinIniString(sectionname, modname, "", renameddll,
668 sizeof(renameddll)-1) > 1)
669 {
670 if(namestart == dllname) {
671 strcpy(dllname, renameddll);
672 }
673 else {
674 *namestart = 0;
675 strcat(dllname, renameddll);
676 }
677 strcat(dllname, ".dll");
678 }
679 return;
680}
681//******************************************************************************
682//******************************************************************************
683Win32DllBase *Win32DllBase::findModule(char *dllname, BOOL fRenameFirst)
684{
685 Win32DllBase *dll;
686 char szDllName[CCHMAXPATH];
687 char *dot, *temp;
688
689//// dprintf2(("findModule %s", dllname));
690
691 strcpy(szDllName, OSLibStripPath(dllname));
692 strupr(szDllName);
693
694 if(fRenameFirst) {
695 renameDll(szDllName, FALSE);
696 }
697
698 dot = strstr(szDllName, ".");
699 if(dot)
700 *dot = 0;
701
702 dlllistmutex.enter();
703 dll = head;
704 while(dll) {
705 if(strcmpi(szDllName, dll->szModule) == 0) {
706 dlllistmutex.leave();
707 return(dll);
708 }
709
710 dll = dll->next;
711 }
712 dlllistmutex.leave();
713 return(NULL);
714}
715//******************************************************************************
716//******************************************************************************
717Win32DllBase *Win32DllBase::findModule(WIN32DLLENTRY DllEntryPoint)
718{
719 dprintf2(("findModule %X", DllEntryPoint));
720
721 dlllistmutex.enter();
722 Win32DllBase *mod = Win32DllBase::head;
723 while(mod != NULL) {
724 dbgCheckObj(mod);
725 if(mod->dllEntryPoint == DllEntryPoint) {
726 dlllistmutex.leave();
727 return(mod);
728 }
729 mod = mod->next;
730 }
731 dlllistmutex.leave();
732 return(NULL);
733}
734//******************************************************************************
735//******************************************************************************
736Win32DllBase *Win32DllBase::findModule(HINSTANCE hinstance)
737{
738 dlllistmutex.enter();
739
740 Win32DllBase *mod = Win32DllBase::head;
741 while(mod != NULL) {
742 dbgCheckObj(mod);
743 if(mod->hinstance == hinstance) {
744 dlllistmutex.leave();
745 return(mod);
746 }
747 mod = mod->next;
748 }
749 dlllistmutex.leave();
750 return(NULL);
751}
752//******************************************************************************
753//******************************************************************************
754Win32DllBase *Win32DllBase::findModuleByAddr(ULONG address)
755{
756 dlllistmutex.enter();
757
758 Win32DllBase *mod = Win32DllBase::head;
759 while(mod != NULL) {
760 dbgCheckObj(mod);
761 if(mod->insideModule(address)) {
762 dlllistmutex.leave();
763 return(mod);
764 }
765 mod = mod->next;
766 }
767 dlllistmutex.leave();
768 return(NULL);
769}
770//******************************************************************************
771//******************************************************************************
772BOOL Win32DllBase::isDll()
773{
774 return TRUE;
775}
776//******************************************************************************
777//******************************************************************************
778void Win32DllBase::setThreadLibraryCalls(BOOL fEnable)
779{
780 // if fEnable == true, do call the ATTACH_THREAD, DETACH_THREAD functions
781 // if fEnable == false, do not call the ATTACH_THREAD, DETACH_THREAD functions
782 fSkipEntryCalls = !fEnable;
783}
784
785//******************************************************************************
786//******************************************************************************
787Win32DllBase *Win32DllBase::head = NULL;
788Queue Win32DllBase::loadLibDlls;
Note: See TracBrowser for help on using the repository browser.