Index: trunk/src/kernel32/KERNEL32.DEF
===================================================================
--- trunk/src/kernel32/KERNEL32.DEF	(revision 3058)
+++ trunk/src/kernel32/KERNEL32.DEF	(revision 3059)
@@ -1,3 +1,3 @@
-; $Id: KERNEL32.DEF,v 1.72 2000-03-03 11:15:58 sandervl Exp $
+; $Id: KERNEL32.DEF,v 1.73 2000-03-09 19:03:19 sandervl Exp $
 
 ;Created by BLAST for IBM's compiler
@@ -20,12 +20,4 @@
    DosQuerySysState            =  DOSCALLS.368
   _DosQuerySysState            =  DOSCALLS.368
-
-  _O32_RegCloseKey             = PMWINX.541
-  _O32_RegCreateKeyEx          = PMWINX.543
-  _O32_RegOpenKeyEx            = PMWINX.550
-  _O32_RegQueryValueEx         = PMWINX.553
-  _O32_RegSetValueEx           = PMWINX.555
-
-
 
 EXPORTS
Index: trunk/src/kernel32/dbglocal.cpp
===================================================================
--- trunk/src/kernel32/dbglocal.cpp	(revision 3058)
+++ trunk/src/kernel32/dbglocal.cpp	(revision 3059)
@@ -1,3 +1,3 @@
-/* $Id: dbglocal.cpp,v 1.2 2000-02-22 19:12:52 sandervl Exp $ */
+/* $Id: dbglocal.cpp,v 1.3 2000-03-09 19:03:18 sandervl Exp $ */
 
 /*
@@ -110,5 +110,7 @@
 "codepage",
 "debug",
-"oslibdebug"
+"oslibdebug",
+"registry",
+"queue"
 };
 //******************************************************************************
Index: trunk/src/kernel32/dbglocal.h
===================================================================
--- trunk/src/kernel32/dbglocal.h	(revision 3058)
+++ trunk/src/kernel32/dbglocal.h	(revision 3059)
@@ -1,3 +1,3 @@
-/* $Id: dbglocal.h,v 1.2 2000-02-22 19:12:53 sandervl Exp $ */
+/* $Id: dbglocal.h,v 1.3 2000-03-09 19:03:18 sandervl Exp $ */
 
 /*
@@ -111,5 +111,7 @@
 #define DBG_debug          90
 #define DBG_oslibdebug     91
-#define DBG_MAXFILES       92
+#define DBG_registry       92
+#define DBG_queue          93
+#define DBG_MAXFILES       94
 
 extern USHORT DbgEnabled[DBG_MAXFILES];
Index: trunk/src/kernel32/initterm.cpp
===================================================================
--- trunk/src/kernel32/initterm.cpp	(revision 3058)
+++ trunk/src/kernel32/initterm.cpp	(revision 3059)
@@ -1,3 +1,3 @@
-/* $Id: initterm.cpp,v 1.36 2000-03-03 11:15:58 sandervl Exp $ */
+/* $Id: initterm.cpp,v 1.37 2000-03-09 19:03:18 sandervl Exp $ */
 
 /*
@@ -47,4 +47,5 @@
 #include "hmdevio.h"
 #include <windllbase.h>
+#include "winexepe2lx.h"
 #include "initsystem.h"
 #include <exitlist.h>
@@ -128,4 +129,12 @@
                 return 0UL;
 
+	    //SvL: Kernel32 is a special case; pe.exe loads it, so increase
+            //     the reference count here
+  	    Win32DllBase *module = Win32DllBase::findModule(hModule);
+  	    if(module && !fPe2Lx) {
+		module->AddRef();
+		module->DisableUnload();
+	    }
+
             /*******************************************************************/
             /* A DosExitList routine must be used to clean up if runtime calls */
Index: trunk/src/kernel32/makefile
===================================================================
--- trunk/src/kernel32/makefile	(revision 3058)
+++ trunk/src/kernel32/makefile	(revision 3059)
@@ -1,3 +1,3 @@
-# $Id: makefile,v 1.89 2000-03-07 11:08:01 bird Exp $
+# $Id: makefile,v 1.90 2000-03-09 19:03:19 sandervl Exp $
 
 #
@@ -117,4 +117,5 @@
 $(OBJDIR)\dbglocal.obj \
 $(OBJDIR)\registry.obj \
+$(OBJDIR)\queue.obj \
 $(OBJDIR)\kernelrsrc.obj
 
@@ -160,5 +161,5 @@
 # Dep rule - makes depenencies for C, C++ and Asm files.
 dep:
-    $(DEPEND) -I$(PDWIN32_INCLUDE);$(PDWIN32_INCLUDE)\win \
+    $(DEPEND) -I. -I$(PDWIN32_INCLUDE);$(PDWIN32_INCLUDE)\win \
         *.c *.cpp *.h *.asm *.inc $(PDWIN32_INCLUDE)\*.h
 
Index: trunk/src/kernel32/misc.cpp
===================================================================
--- trunk/src/kernel32/misc.cpp	(revision 3058)
+++ trunk/src/kernel32/misc.cpp	(revision 3059)
@@ -1,3 +1,3 @@
-/* $Id: misc.cpp,v 1.19 2000-01-25 21:00:39 sandervl Exp $ */
+/* $Id: misc.cpp,v 1.20 2000-03-09 19:03:19 sandervl Exp $ */
 
 /*
@@ -316,8 +316,4 @@
 
     va_start(argptr, tekst);
-    if(thdb) { 
-	thdb->logfile = (DWORD)flog;
-    	fprintf(flog, "t%d", thdb->threadId);
-    }
     vfprintf((FILE *)logfile, tekst, argptr);
     if(thdb) thdb->logfile = 0;
Index: trunk/src/kernel32/mmap.cpp
===================================================================
--- trunk/src/kernel32/mmap.cpp	(revision 3058)
+++ trunk/src/kernel32/mmap.cpp	(revision 3059)
@@ -1,3 +1,3 @@
-/* $Id: mmap.cpp,v 1.35 2000-03-02 19:17:21 sandervl Exp $ */
+/* $Id: mmap.cpp,v 1.36 2000-03-09 19:03:19 sandervl Exp $ */
 
 /*
@@ -502,5 +502,4 @@
 }
 //******************************************************************************
-//Assumes mutex has been acquired
 //******************************************************************************
 void Win32MemMap::deleteAll()
@@ -510,4 +509,5 @@
 
   //delete all maps created by this process
+  globalviewMutex.enter();
   while(map) {
 	nextmap = map->next;
@@ -525,4 +525,5 @@
 	map = nextmap;
   }
+  globalviewMutex.leave();
 }
 //******************************************************************************
@@ -691,4 +692,5 @@
   Win32MemMapView *view = mapviews;
 
+  globalviewMutex.enter();
   if(view != NULL) {
   	while(view) {
@@ -700,4 +702,5 @@
 	}
   }
+  globalviewMutex.leave();
   return view;
 }
Index: trunk/src/kernel32/queue.cpp
===================================================================
--- trunk/src/kernel32/queue.cpp	(revision 3059)
+++ trunk/src/kernel32/queue.cpp	(revision 3059)
@@ -0,0 +1,152 @@
+/* $Id: queue.cpp,v 1.1 2000-03-09 19:03:20 sandervl Exp $ */
+
+/*
+ * Very simply generic queue class
+ *
+ * Copyright 2000 Sander van Leeuwen (sandervl@xs4all.nl)
+ *
+ * Project Odin Software License can be found in LICENSE.TXT
+ *
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <os2win.H>
+#include <misc.h>
+#include "queue.h"
+
+#define DBG_LOCALLOG	DBG_queue
+#include "dbglocal.h"
+
+//******************************************************************************
+//******************************************************************************
+Queue::Queue()
+{
+    head = tail = NULL;
+}
+//******************************************************************************
+//******************************************************************************
+Queue::~Queue()
+{
+    while(hasElements()) {
+        Pop();
+    }
+}
+//******************************************************************************
+//******************************************************************************
+void Queue::operator=(Queue& queue) 
+{
+ QueueItem *item = queue.Head();
+
+  if(item)
+  	PushRev(queue, item);
+}
+//******************************************************************************
+//******************************************************************************
+void Queue::PushRev(Queue& queue, QueueItem *item)
+{
+ QueueItem *nextitem = queue.getNext(item);
+
+  if(nextitem) {
+	PushRev(queue, nextitem);
+  }
+  Push(queue.getItem(item));
+}
+//******************************************************************************
+//******************************************************************************
+void Queue::Push(ULONG dwItemData)
+{
+ QueueItem *item;
+
+    item = new QueueItem(dwItemData);
+    if(item == NULL) {
+        DebugInt3();
+        return;
+    }
+    if(head == NULL) {
+        head = item;
+        tail = item;
+        item->next = NULL;
+    }
+    else {
+        item->next = head;
+        head = item;
+    }
+}
+//******************************************************************************
+//******************************************************************************
+void Queue::Remove(ULONG dwItemData)
+{
+ QueueItem *item = head, *tmp;
+
+    if(item == NULL) {
+	DebugInt3();
+	return;
+    }
+    if(item->dwItemData == dwItemData) {
+	head = item->next;
+	delete item;
+	return;
+    }
+    while(item->next) {
+    	if(item->next->dwItemData == dwItemData) {
+		tmp = item->next;
+		item->next = tmp->next;
+		delete tmp;
+		return;
+	}
+	item = item->next;
+    }
+    DebugInt3();
+    dprintf(("Queue::Remove: item %x not found!", dwItemData));
+}
+//******************************************************************************
+//******************************************************************************
+void Queue::Remove(QueueItem *removeitem)
+{
+ QueueItem *item = head, *tmp;
+
+    if(item == NULL) {
+	DebugInt3();
+	return;
+    }
+    if(item == removeitem) {
+	head = item->next;
+	delete item;
+	return;
+    }
+    while(item->next) {
+    	if(item->next == removeitem) {
+		tmp = item->next;
+		item->next = tmp->next;
+		delete tmp;
+		return;
+	}
+	item = item->next;
+    }
+    DebugInt3();
+    dprintf(("Queue::Remove: item %x not found!", removeitem));
+}
+//******************************************************************************
+//******************************************************************************
+ULONG Queue::Pop()
+{
+ QueueItem *item;
+ ULONG itemdata;
+
+    if(head == NULL) {
+	DebugInt3();
+        return NULL;
+    }
+    item = head;
+    head = item->next;
+    if(head == NULL) {
+        tail = NULL;
+    }
+    itemdata = item->dwItemData;
+    delete item;
+    return itemdata;
+}
+//******************************************************************************
+//******************************************************************************
+
Index: trunk/src/kernel32/queue.h
===================================================================
--- trunk/src/kernel32/queue.h	(revision 3059)
+++ trunk/src/kernel32/queue.h	(revision 3059)
@@ -0,0 +1,61 @@
+/* $Id: queue.h,v 1.1 2000-03-09 19:03:20 sandervl Exp $ */
+
+/*
+ * Very simply generic queue class
+ *
+ * Copyright 2000 Sander van Leeuwen (sandervl@xs4all.nl)
+ *
+ * Project Odin Software License can be found in LICENSE.TXT
+ *
+ */
+
+class Queue;
+
+//******************************************************************************
+//******************************************************************************
+class QueueItem
+{
+public:
+    QueueItem::QueueItem(ULONG dwItemData)
+    {
+        this->dwItemData = dwItemData;
+        next = NULL;
+    }
+
+private:
+    ULONG       dwItemData;
+    QueueItem  *next;
+
+    friend class Queue;
+};
+//******************************************************************************
+//******************************************************************************
+class Queue
+{
+public:
+    Queue();
+    ~Queue();
+
+    void       Push(ULONG dwItemData);
+    void       Remove(ULONG dwItemData);
+    void       Remove(QueueItem *item);
+    ULONG      Pop();
+
+    void       operator=(Queue&) ;
+
+    QueueItem *Head()                   { return head; };
+    QueueItem *Tail()                   { return tail; };
+    QueueItem *getNext(QueueItem *item) { return item->next; };
+    ULONG      getItem(QueueItem *item) { return item->dwItemData; };
+
+    BOOL       hasElements()            { return head != NULL; };
+
+private:
+    void       PushRev(Queue& queue, QueueItem *item);
+
+    QueueItem *head;
+    QueueItem *tail;
+};
+//******************************************************************************
+//******************************************************************************
+
Index: trunk/src/kernel32/windllbase.cpp
===================================================================
--- trunk/src/kernel32/windllbase.cpp	(revision 3058)
+++ trunk/src/kernel32/windllbase.cpp	(revision 3059)
@@ -1,3 +1,3 @@
-/* $Id: windllbase.cpp,v 1.10 2000-03-04 19:52:36 sandervl Exp $ */
+/* $Id: windllbase.cpp,v 1.11 2000-03-09 19:03:20 sandervl Exp $ */
 
 /*
@@ -6,7 +6,10 @@
  * Copyright 1998-1999 Sander van Leeuwen (sandervl@xs4all.nl)
  *
- * TODO: Unloading of system dlls is not correct for the PE loader
- *       (they're always put at the head of the list even though there
- *        might be a dependency with a win32 dll)
+ * Unloading of a dll always happens in order of dependency (taking nr of
+ * loads into account)
+ * Unloading of dynamically loaded dll (with LoadLibrary) in deleteAll
+ * is done in LIFO order (NT exhibits the same behaviour)
+ *           
+ * RemoveCircularDependency: TODO: Send process detach message here??
  *
  * Project Odin Software License can be found in LICENSE.TXT
@@ -26,5 +29,5 @@
 #include <fstream.h>
 #include <misc.h>
-#include <win32type.h>
+#include <win32api.h>
 #include <pefile.h>
 #include <windllbase.h>
@@ -48,46 +51,12 @@
                            Win32ImageBase *parent)
                  : Win32ImageBase(hinstance),
-  	           referenced(0), fSkipEntryCalls(FALSE),
-                   fAttachedToProcess(FALSE), fUnloaded(FALSE), fDynamicLoad(FALSE)
+  	           referenced(0), fSkipEntryCalls(FALSE), next(NULL), fInserted(FALSE),
+                   fAttachedToProcess(FALSE), fUnloaded(FALSE), 
+                   nrDynamicLibRef(0), fLoadLibrary(FALSE), fDisableUnload(FALSE)
 {
   dllEntryPoint = DllEntryPoint;
 
-  dlllistmutex.enter();
-  //unload of dlls needs to be done in reverse order of dependencies
-  //Note: Only necessary for pe loader; the OS/2 loader takes care of this 
-  //for win32k/pe2lx 
-  if(parent && parent->isDll()) {
-	Win32DllBase *dll = head;
-	while(dll) {
-		if(dll->getInstanceHandle() == parent->getInstanceHandle()) {
-			break;
-		}
-		dll = dll->next;
-	}
-	if(dll) {
-		//insert this dll in list after it's parent
-		next = dll->next;
-		dll->next = this;
-	}
-	else 	DebugInt3();
-  }
-  else {
-  	next = head;
-  	head = this;
-  }
-  dlllistmutex.leave();
-
-#ifdef DEBUG_ENABLELOG_LEVEL2
-  dlllistmutex.enter();
-  Win32DllBase *dll = head;
-
-  dprintf2(("Win32DllBase::Win32DllBase: List of loaded dlls:"));
-  while(dll) {
-	dprintf2(("DLL %s", dll->szModule));
-	dll = dll->next;
-  }
-  dlllistmutex.leave();
-#endif
-
+  setUnloadOrder(parent);
+  
   dprintf(("Win32DllBase::Win32DllBase %x %s", hinstance, szModule));
 }
@@ -122,16 +91,296 @@
 }
 //******************************************************************************
-//ASSUMPTION: called by FreeLibrary
+//******************************************************************************
+void Win32DllBase::loadLibrary()
+{
+  //dummy
+}
+//******************************************************************************
+//******************************************************************************
+void Win32DllBase::incDynamicLib()
+{ 
+  if(nrDynamicLibRef == 0) {
+  	dlllistmutex.enter();
+	loadLibDlls.Push((ULONG)this);
+	dlllistmutex.leave();
+  }
+  nrDynamicLibRef++; 
+}
+//******************************************************************************
+//******************************************************************************
+void Win32DllBase::decDynamicLib()
+{ 
+  nrDynamicLibRef--; 
+  if(nrDynamicLibRef == 0) {
+  	dlllistmutex.enter();
+	loadLibDlls.Remove((ULONG)this);
+	dlllistmutex.leave();
+  }
+}
+//******************************************************************************
+//unload of dlls needs to be done in reverse order of dependencies
+//Note: Only necessary for pe loader; the OS/2 loader takes care of this 
+//for win32k/pe2lx 
+//******************************************************************************
+void Win32DllBase::setUnloadOrder(Win32ImageBase *parent)
+{
+ Win32DllBase *dll;
+ Win32DllBase *parentdll = NULL;
+
+  dlllistmutex.enter();
+  if(parent) {
+  	dll = head;
+	while(dll) {
+		if(dll->getInstanceHandle() == parent->getInstanceHandle()) {
+			parentdll = dll;
+			break;
+		}
+		dll = dll->next;
+	}
+  }
+
+  //first check if this dll is already at a lower position (further down the list)
+  //than the parent
+  if(parentdll && fInserted) {//already in the list?
+  	dll = parentdll->next;
+  	while(dll) {
+		if(dll->getInstanceHandle() == getInstanceHandle()) {
+  			dlllistmutex.leave();
+			return; //it's at a lower position, so no need to change anything
+		}
+		dll = dll->next;
+  	}
+
+	//it's already in the list but not at the right position; remove it now
+	if(head == this) {
+		head = next;
+	}
+	else {
+		dll = head;
+		while(dll->next) {
+			if(dll->next == this) {
+				dll->next = next;
+				break;
+			}
+			dll = dll->next;
+		}
+	}
+  }
+  else 
+  if(fInserted) {//already in the list?
+  	dlllistmutex.leave();
+	return;
+  }
+  //(re)insert it in the list after it's parent
+  if(parentdll) {
+	next = parentdll->next;
+	parentdll->next = this;
+  }
+  else {//no parent or exe, just add it at the start of the list
+  	next = head;
+  	head = this;
+  }
+  fInserted = TRUE;
+
+  //Now do the same thing for the child dependencies
+  QueueItem *item;
+
+  item = loadedDlls.Head();
+  while(item) {
+	dll = (Win32DllBase *)loadedDlls.getItem(item);
+	//Check for circular dependencies (i.e. in Lotus Notes)
+	if(dll != parentdll) {
+  		dll->setUnloadOrder(this);
+	}
+
+	item  = loadedDlls.getNext(item);
+  }
+
+  dlllistmutex.leave();
+}
+//******************************************************************************
+//******************************************************************************
+#ifdef DEBUG
+ULONG Win32DllBase::AddRef(char *parentname)
+#else
+ULONG Win32DllBase::AddRef()
+#endif
+{ 
+ Win32DllBase *dll;
+
+  dprintf(("Win32DllBase::AddRef %s->%s %d", parentname, getModuleName(), referenced+1));
+  ++referenced;
+#ifdef DEBUG
+  if(referenced == 1) {
+#ifdef DEBUG_ENABLELOG_LEVEL2
+	printListOfDlls();
+#endif
+	//printDependencies(NULL);
+  }
+#endif
+
+  return referenced; 
+}
+//******************************************************************************
 //******************************************************************************
 ULONG Win32DllBase::Release()
 {
- ULONG ret = --referenced;
-
-  if(ret == 0) {
-	dprintf(("Win32DllBase::Release, referenced == 0\n"));
+ Queue         queue;
+ QueueItem    *item;
+ Win32DllBase *dll;
+ LONG          ret;
+
+  dprintf(("Win32DllBase::Release %s %d", getModuleName(), referenced-1));
+
+  ret = --referenced;
+  if(ret <= 0) {
+	//make copy of linked list of dependencies
+	queue = loadedDlls;
+
+	//remove any circular dependencies on this dll that might be present
+  	item = queue.Head();
+  	while(item) {
+		dll = (Win32DllBase *)queue.getItem(item);
+		if(dll == NULL) {
+			dprintf(("ERROR: Win32DllBase::Release: dll item == NULL!!"));
+			DebugInt3();
+			return -1;
+		}
+		dll->RemoveCircularDependency(this);
+		item = queue.getNext(item);
+	}
+#ifdef DEBUG
+	//printDependencies(NULL);
+#endif
+	dprintf(("Win32DllBase::Release %s referenced == 0", getModuleName()));
+
+	//delete dll object
 	delete this;
+
+	//unreference all of it's dependencies
+  	item = queue.Head();
+  	while(item) {
+		dll = (Win32DllBase *)queue.getItem(item);
+		if(dll == NULL) {
+			dprintf(("ERROR: Win32DllBase::Release: dll item == NULL!!"));
+			DebugInt3();
+			return -1;
+		}
+		dll->Release();
+		item = queue.getNext(item);
+	}
   }
   return(ret);
 }
+//******************************************************************************
+//Lotus Notes has several ugly circular dependencies in it's dlls.
+//Remove them before they cause problems.
+//******************************************************************************
+BOOL Win32DllBase::RemoveCircularDependency(Win32DllBase *parent)
+{
+ QueueItem    *item, *tmp;
+ Win32DllBase *dll;
+ BOOL          ret = FALSE;
+
+  //remove any circular dependencies on this dll that might be present
+  item = loadedDlls.Head();
+  while(item) {
+	dll = (Win32DllBase *)loadedDlls.getItem(item);
+	if(dll == NULL) {
+		dprintf(("ERROR: Win32DllBase::Release: dll item == NULL!!"));
+		DebugInt3();
+		return FALSE;
+	}
+	tmp = loadedDlls.getNext(item);
+	if(dll == parent) {
+		dprintf(("Removing CIRCULAR dependency %s->%s", parent->getModuleName(), dll->getModuleName()));
+		loadedDlls.Remove(item);
+		ret = TRUE;
+	}
+////	else	ret |= dll->RemoveCircularDependency(parent);
+	item = tmp;
+  }
+  //TODO: Send process detach message here??
+  return ret;
+}
+//******************************************************************************
+//There's a slight problem with our dependency procedure. 
+//example: gdi32 is loaded -> depends on kernel32 (which is already loaded)
+//         kernel32's reference count isn't updated
+//         (when we load gdi32, we don't know which dlls it depends on and which
+//          of those are already loaded and which aren't)
+//-> solution: Determine reference counts of dependant lx dlls and update those
+//             reference counts
+//******************************************************************************
+void Win32DllBase::updateDependencies()
+{
+ QueueItem    *item;
+ Win32DllBase *dll, *depdll;
+ ULONG         refcount;
+ 
+  dlllistmutex.enter();
+  item = loadedDlls.Head();
+  while(item) {
+	depdll   = (Win32DllBase *)loadedDlls.getItem(item);
+	if(depdll == NULL) {
+		dprintf(("updateDependencies: depdll == NULL!!"));
+		DebugInt3();	
+		return;
+	}
+	refcount = 0;
+  	dll      = head;
+
+  	while(dll) {
+		if(dll->dependsOn(depdll)) {
+			refcount++;
+		}
+		dll = dll->getNext();
+	}
+	if(refcount > depdll->referenced) {
+		dprintf(("Win32DllBase::updateDependencies changing refcount of %s to %d (old=%d)", depdll->getModuleName(), refcount, depdll->referenced));
+		depdll->referenced = refcount;
+	}
+
+	item = loadedDlls.getNext(item);
+  }
+  dlllistmutex.leave();
+}
+//******************************************************************************
+//******************************************************************************
+#ifdef DEBUG
+void Win32DllBase::printDependencies(char *parent)
+{
+ QueueItem    *item;
+ Win32DllBase *dll;
+ ULONG         ret;
+
+  dprintf(("Dependency list: %s->%s %d", parent, getModuleName(), referenced));
+  item = loadedDlls.Head();
+  while(item) {
+	dll = (Win32DllBase *)loadedDlls.getItem(item);
+	if(dll == NULL) {
+		return;
+	}
+	dll->printDependencies(getModuleName());
+	item = loadedDlls.getNext(item);
+  }
+}
+//******************************************************************************
+//******************************************************************************
+#ifdef DEBUG_ENABLELOG_LEVEL2
+void Win32DllBase::printListOfDlls()
+{
+ Win32DllBase *dll;
+
+  dll = head;
+
+  dprintf2(("Win32DllBase::Win32DllBase: List of loaded dlls:"));
+  while(dll) {
+	dprintf2(("DLL %s %d", dll->szModule, dll->referenced));
+	dll = dll->next;
+  }
+}
+#endif
+#endif
 //******************************************************************************
 //******************************************************************************
@@ -252,4 +501,5 @@
 void Win32DllBase::attachThreadToAllDlls()
 {
+  dlllistmutex.enter();
   Win32DllBase *dll = Win32DllBase::head;
   while(dll) {
@@ -257,4 +507,5 @@
 	dll = dll->getNext();
   }
+  dlllistmutex.leave();
 }
 //******************************************************************************
@@ -263,4 +514,5 @@
 void Win32DllBase::detachThreadFromAllDlls()
 {
+  dlllistmutex.enter();
   Win32DllBase *dll = Win32DllBase::head;
   while(dll) {
@@ -268,4 +520,5 @@
 	dll = dll->getNext();
   }
+  dlllistmutex.leave();
 }
 //******************************************************************************
@@ -274,4 +527,5 @@
 void Win32DllBase::tlsAttachThreadToAllDlls()
 {
+  dlllistmutex.enter();
   Win32DllBase *dll = Win32DllBase::head;
   while(dll) {
@@ -279,4 +533,5 @@
 	dll = dll->getNext();
   }
+  dlllistmutex.leave();
 }
 //******************************************************************************
@@ -285,4 +540,5 @@
 void Win32DllBase::tlsDetachThreadFromAllDlls()
 {
+  dlllistmutex.enter();
   Win32DllBase *dll = Win32DllBase::head;
   while(dll) {
@@ -290,31 +546,63 @@
 	dll = dll->getNext();
   }
-}
-//******************************************************************************
-//******************************************************************************
-void Win32DllBase::deleteAll(BOOL fDynamicLoad)
-{
- Win32DllBase *dll = Win32DllBase::head, *tmp;
-
-#ifdef DEBUG
-  dlllistmutex.enter();
-
-  dprintf(("Win32DllBase::deleteAll: List of loaded dlls:"));
+  dlllistmutex.leave();
+}
+//******************************************************************************
+//******************************************************************************
+void Win32DllBase::deleteAll()
+{
+ Win32DllBase *dll = Win32DllBase::head;
+
+  dprintf(("Win32DllBase::deleteAll"));
+
+#ifdef DEBUG_ENABLELOG_LEVEL2
+  if(dll) dll->printListOfDlls();
+#endif
+
+  dlllistmutex.enter();
   while(dll) {
-	dprintf(("DLL %s", dll->szModule));
-	dll = dll->next;
-  }
-  dlllistmutex.leave();
-  dll = Win32DllBase::head;
+	dll->Release();
+	dll = Win32DllBase::head;
+  }
+  dlllistmutex.leave();
+  dprintf(("Win32DllBase::deleteAll Done!"));
+}
+//******************************************************************************
+//Delete dlls loaded by LoadLibrary(Ex) in LIFO order
+//******************************************************************************
+void Win32DllBase::deleteDynamicLibs()
+{
+ Win32DllBase *dll = head;
+ QueueItem    *item;
+
+  dprintf(("Win32DllBase::deleteDynamicLibs"));
+#ifdef DEBUG_ENABLELOG_LEVEL2
+  if(dll) dll->printListOfDlls();
 #endif
 
-  while(dll) {
-	if(fDynamicLoad || !dll->fDynamicLoad) {
-		tmp = dll->next;
-		dll->Release();
-		dll = tmp;
-	}
-	else	dll = dll->next;
-  }
+  dlllistmutex.enter();
+
+  item = loadLibDlls.Head();
+  while(item) {
+	dll = (Win32DllBase *)loadLibDlls.getItem(item);
+	int dynref = dll->nrDynamicLibRef;
+	if(dynref) {
+  		while(dynref) {
+			dynref--;
+        		dll->decDynamicLib();
+			dll->Release();
+		}
+	}
+	else	DebugInt3();
+  	item = loadLibDlls.Head(); //queue could have been changed, so start from the beginning
+  }
+
+  dlllistmutex.leave();
+}
+//******************************************************************************
+//******************************************************************************
+Win32DllBase *Win32DllBase::getFirst()
+{
+  return head;
 }
 //******************************************************************************
@@ -386,5 +674,5 @@
 //******************************************************************************
 //******************************************************************************
-Win32DllBase *Win32DllBase::findModule(char *dllname)
+Win32DllBase *Win32DllBase::findModule(char *dllname, BOOL fRenameFirst)
 {
  Win32DllBase *dll;
@@ -392,8 +680,13 @@
  char *dot, *temp;
 
-  dprintf(("findModule %s", dllname));
+////  dprintf2(("findModule %s", dllname));
 
   strcpy(szDllName, OSLibStripPath(dllname));
   strupr(szDllName);
+
+  if(fRenameFirst) {
+	renameDll(szDllName, FALSE);
+  }
+
   dot = strstr(szDllName, ".");
   if(dot)
@@ -417,5 +710,5 @@
 Win32DllBase *Win32DllBase::findModule(WIN32DLLENTRY DllEntryPoint)
 {
-   dprintf(("findModule %X", DllEntryPoint));
+   dprintf2(("findModule %X", DllEntryPoint));
 
    dlllistmutex.enter();
@@ -468,2 +761,3 @@
 //******************************************************************************
 Win32DllBase *Win32DllBase::head = NULL;
+Queue         Win32DllBase::loadLibDlls;
Index: trunk/src/kernel32/windllbase.h
===================================================================
--- trunk/src/kernel32/windllbase.h	(revision 3059)
+++ trunk/src/kernel32/windllbase.h	(revision 3059)
@@ -0,0 +1,151 @@
+/* $Id: windllbase.h,v 1.1 2000-03-09 19:03:21 sandervl Exp $ */
+
+/*
+ * Win32 Dll base class
+ *
+ * Copyright 1998-1999 Sander van Leeuwen (sandervl@xs4all.nl)
+ *
+ *
+ * Project Odin Software License can be found in LICENSE.TXT
+ *
+ */
+#ifndef __WINDLLBASE_H__
+#define __WINDLLBASE_H__
+
+#include <winimagebase.h>
+#include <odinlx.h>
+#include <vmutex.h>
+
+#ifndef HINSTANCE
+#define HINSTANCE ULONG
+#endif
+
+#define DLL_PROCESS_ATTACH 1
+#define DLL_THREAD_ATTACH  2
+#define DLL_THREAD_DETACH  3
+#define DLL_PROCESS_DETACH 0
+
+#define DONT_RESOLVE_DLL_REFERENCES     0x00000001
+#define LOAD_LIBRARY_AS_DATAFILE        0x00000002
+#define LOAD_WITH_ALTERED_SEARCH_PATH   0x00000008
+
+//odin.ini section names to lookup renamed dlls
+//i.e. OLE32 -> OLE32OS2
+#define DLLRENAMEWIN_SECTION 	"DLLRENAMEWIN"
+//i.e. OLE32OS2 -> OLE32
+#define DLLRENAMEOS2_SECTION    "DLLRENAMEOS2"
+
+class Win32DllBase : public virtual Win32ImageBase
+{
+public:
+                  Win32DllBase(HINSTANCE hInstance, WIN32DLLENTRY DllEntryPoint, Win32ImageBase *parent = NULL);
+virtual          ~Win32DllBase();
+
+#ifdef DEBUG
+virtual	ULONG     AddRef(char *parentname = NULL);
+#else
+virtual ULONG     AddRef();
+#endif
+virtual	ULONG     Release();
+
+	char     *getName()          { return szModule; };
+	void      setNoEntryCalls()  { fSkipEntryCalls = TRUE; };
+
+	Win32DllBase *getNext()  { return next; };
+static 	Win32DllBase *getFirst();
+
+//Send DLL_THREAD_ATTACH message to all dlls for a new thread
+static  void      attachThreadToAllDlls();
+
+//Send DLL_THREAD_DETACH message to all dlls for thread that's about to die
+static  void      detachThreadFromAllDlls();
+
+//Setup TLS structure for all dlls for a new thread
+static  void      tlsAttachThreadToAllDlls();
+
+//Destroy TLS structure for all dlls for a thread that's about to die
+static  void      tlsDetachThreadFromAllDlls();
+
+	BOOL      attachProcess();
+	BOOL      detachProcess();
+	BOOL      attachThread();
+	BOOL      detachThread();
+
+	// enable / disable thread attach/detach calls
+	void      setThreadLibraryCalls(BOOL fEnable);
+
+	//This counter is incremented when the dll has been loaded with LoadLibrary(Ex)
+        //(== not loaded on behalf of another dll or the main exe)
+	void      incDynamicLib();
+	void      decDynamicLib();
+	BOOL      isDynamicLib()   { return nrDynamicLibRef != 0; };
+
+	void      setUnloadOrder(Win32ImageBase *parent);
+
+	void      updateDependencies();
+
+	BOOL      RemoveCircularDependency(Win32DllBase *parent);
+
+	// Loaded by DosLoadModule
+virtual	void      setLoadLibrary() { fLoadLibrary = TRUE; };
+
+	// isLoaded returns TRUE when a dll has been loaded with DosLoadModule
+virtual BOOL      isLoaded()       { return fLoadLibrary; };
+
+	//Should only be called to make sure DosLoadModule is called at least 
+        //once for a dll (to make sure OS/2 doesn't unload the dll when it's
+        //still needed)
+virtual	void      loadLibrary();
+
+	//Only called for kernel32
+	void      DisableUnload()  { fDisableUnload = TRUE; };
+
+static  void      deleteDynamicLibs();
+static  void      deleteAll();
+
+static	BOOL      isSystemDll(char *szFileName);
+
+virtual BOOL      isLxDll() = 0;
+virtual BOOL      isDll();
+
+static  void      renameDll(char *dllname, BOOL fWinToOS2=TRUE);
+static  void      setDefaultRenaming();
+
+static  Win32DllBase *findModule(char *dllname, BOOL fRenameFirst = FALSE);
+static  Win32DllBase *findModule(HINSTANCE hinstance);
+static  Win32DllBase *findModule(WIN32DLLENTRY DllEntryPoint);
+
+#ifdef DEBUG_ENABLELOG_LEVEL2
+	void          printListOfDlls();
+#endif
+
+protected:
+#ifdef DEBUG
+	void          printDependencies(char *parent);
+#endif
+
+	BOOL          fSkipEntryCalls, fUnloaded, fAttachedToProcess;
+
+	WIN32DLLENTRY dllEntryPoint;
+
+	LONG          referenced;
+
+	//This counter is incremented when the dll has been loaded with LoadLibrary(Ex)
+        //(== not loaded on behalf of another dll or the main exe)
+	BOOL          nrDynamicLibRef;
+
+	BOOL          fInserted; //inserted in dll list
+
+	//This flag is set when a dll has been loaded with DosLoadModule
+        BOOL          fLoadLibrary;
+	BOOL	      fDisableUnload;
+
+private:
+static  Queue         loadLibDlls;
+static  Win32DllBase *head;
+	Win32DllBase *next;
+};
+
+extern VMutex dlllistmutex;   //protects linked lists of heaps
+
+#endif
Index: trunk/src/kernel32/windlllx.cpp
===================================================================
--- trunk/src/kernel32/windlllx.cpp	(revision 3058)
+++ trunk/src/kernel32/windlllx.cpp	(revision 3059)
@@ -1,15 +1,11 @@
-/* $Id: windlllx.cpp,v 1.8 2000-02-16 14:22:11 sandervl Exp $ */
+/* $Id: windlllx.cpp,v 1.9 2000-03-09 19:03:21 sandervl Exp $ */
 
 /*
  * Win32 LX Dll class (compiled in OS/2 using Odin32 api)
  *
- * Copyright 1999 Sander van Leeuwen (sandervl@xs4all.nl)
- *
+ * Copyright 1999-2000 Sander van Leeuwen (sandervl@xs4all.nl)
  *
  * TODO: Unloading of dlls probably needs to be fixed due to OS/2 bug 
  *       (wrong unload order of dlls)
- * TODO: Unloading of system dlls is not correct for the PE loader
- *       (they're always put at the head of the list even though there
- *        might be a dependency with a win32 dll)
  *
  * Project Odin Software License can be found in LICENSE.TXT
@@ -23,4 +19,5 @@
 #define INCL_WIN
 #include <os2wrap.h>	//Odin32 OS/2 api wrappers
+#include <os2newapi.h>
 #include <stdio.h>
 #include <string.h>
@@ -32,6 +29,9 @@
 #include <windllbase.h>
 #include <windlllx.h>
+#include "winexepe2lx.h"
 #include <odinlx.h>
 #include "oslibmisc.h"
+
+#include <exe386.h>
 
 #define DBG_LOCALLOG	DBG_windlllx
@@ -47,4 +47,5 @@
 {
  Win32LxDll *windll;
+ Win32DllBase *windlldep;
 
    windll = (Win32LxDll *)Win32DllBase::findModule(hInstance);
@@ -59,9 +60,55 @@
 	return FALSE;
    }
-   windll->AddRef();
-   if(windll->attachProcess() == 0)
-	return 0;
-
+   if(fPe2Lx) {
+   	windll->AddRef();
+
+   	if(windll->attachProcess() == 0)
+		return 0;
+
+   	return windll->getInstanceHandle();
+   }
+   IMAGE_DOS_HEADER doshdr;
+   struct e32_exe   lxhdr;
+   ULONG            offset;
+   char             modulename[CCHMAXPATH];
+   char             modsize;
+   APIRET           rc;
+   int              i;
+
+   //SvL: This code reads the import name table of the dll to get the dependencies
+   //     on other dlls.
+   //DosQueryHeaderInfo is an undocumented api, but works very well.
+   //(no need to save FS here as we'll return to OS/2 immediately)
+   rc = DosQueryHeaderInfo(hInstance, 0, &doshdr, sizeof(IMAGE_DOS_HEADER), QHINF_READFILE);
+   if(rc) {
+	goto hdrerror;
+   }
+   rc = DosQueryHeaderInfo(hInstance, doshdr.e_lfanew, &lxhdr, sizeof(e32_exe), QHINF_READFILE);
+   if(rc) {
+	goto hdrerror;
+   }
+   offset = doshdr.e_lfanew + lxhdr.e32_impmod;
+   for(i=0;i<lxhdr.e32_impmodcnt;i++) {
+   	rc = DosQueryHeaderInfo(hInstance, offset, &modsize, 1, QHINF_READFILE);
+   	if(rc) {
+		goto hdrerror;
+   	}
+   	rc = DosQueryHeaderInfo(hInstance, offset+1, &modulename, min(modsize, sizeof(modulename)), QHINF_READFILE);
+   	if(rc) {
+		goto hdrerror;
+   	}
+	modulename[modsize] = 0;
+   	windlldep = Win32DllBase::findModule(modulename, TRUE);
+   	if(windlldep) {
+		dprintf(("RegisterLxDll: Add dependency %s -> %s", windll->getModuleName(), modulename));
+		windll->addDependency(windlldep);
+	}
+	offset += modsize + 1;
+   }
    return windll->getInstanceHandle();
+
+hdrerror:
+   dprintf(("DosQueryHeaderInfo returned %d", rc));
+   return windll->getInstanceHandle();
 }
 //******************************************************************************
@@ -70,18 +117,20 @@
 BOOL WIN32API UnregisterLxDll(HINSTANCE hInstance)
 {
-#if 1
-   return TRUE;
-#else
  Win32LxDll *windll;
+
+   //Don't proceed for pe2lx/win32k (os/2 dll unload dependency bug)
+   //Don't do it either after ExitProcess has been called
+   if(fPe2Lx || WinExe == NULL)
+   	return TRUE;
 
    windll = (Win32LxDll *)Win32DllBase::findModule(hInstance);
    if(!windll) {
-	dprintf(("UnregisterLxDll: Can't find dll with handle %x!!!", hInstance));
-	return FALSE;
-   }
-   windll->detachProcess();
+	dprintf(("UnregisterLxDll: Can't find dll with handle %x (already deleted)", hInstance));
+	return TRUE; //already deleted by Win32LxDll::Release
+   }
+   dprintf(("UnregisterLxDll %s", windll->getModuleName()));
+   //This can only happen for LX dependencies (i.e. wininet loads wsock32)
    delete windll;
    return TRUE;
-#endif
 }
 //******************************************************************************
@@ -101,21 +150,94 @@
 Win32LxDll::~Win32LxDll()
 {
-  dprintf(("Win32LxDll::~Win32LxDll %s", szModule));
-}
-//******************************************************************************
-//ASSUMPTION: called by FreeLibrary
+}
+//******************************************************************************
+//Load it again so OS/2 takes care of the reference count (to make sure
+//a dll isn't unloaded when the win32 app still needs it)
+//******************************************************************************
+void Win32LxDll::loadLibrary()
+{
+ char   szModuleFailure[CCHMAXPATH] = "";
+ ULONG  hInstanceNewDll;
+ APIRET rc;
+
+  if(fLoadLibrary) {
+	DebugInt3();
+	return;
+  }
+
+  dprintf(("Win32LxDll::loadLibrary %s", getModuleName()));
+  rc = DosLoadModule(szModuleFailure, sizeof(szModuleFailure), getFullPath(), (HMODULE *)&hInstanceNewDll);
+  if(rc) {
+	dprintf(("DosLoadModule returned %X for %s\n", rc, szModuleFailure));
+	DebugInt3(); //should NEVER happen
+	return;
+  }
+  //only do this once, so set the fLoadLibrary flag to true
+  setLoadLibrary();
+}
+//******************************************************************************
+//******************************************************************************
+#ifdef DEBUG
+ULONG Win32LxDll::AddRef(char *parentname)
+#else
+ULONG Win32LxDll::AddRef()
+#endif
+{
+ Win32DllBase *dll;
+ QueueItem    *item;
+ ULONG         ret;
+
+#ifdef DEBUG
+  ret = Win32DllBase::AddRef(parentname);
+#else
+  ret = Win32DllBase::AddRef();
+#endif
+
+  if(fPe2Lx)
+	return ret;
+
+  if(referenced == 1) 
+  {
+  	item = loadedDlls.Head();
+  	while(item) {
+		dll = (Win32DllBase *)loadedDlls.getItem(item);
+		if(dll == NULL) {
+			dprintf(("ERROR: Win32DllBase::AddRef: dll item == NULL!!"));
+			DebugInt3();
+			return -1;
+		}
+#ifdef DEBUG
+		dll->AddRef(getModuleName());
+#else
+		dll->AddRef();
+#endif
+		item = loadedDlls.getNext(item);
+	}
+   	if(attachProcess() == 0)
+		return 0;
+  }
+  return ret;  
+}
+//******************************************************************************
 //******************************************************************************
 ULONG Win32LxDll::Release()
 { 
- ULONG ret = --referenced;
  HINSTANCE hinst;
-
-  if(ret == 0) {
-	dprintf(("Win32LxDll::Release, referenced == 0\n"));
+ ULONG     ret;
+ APIRET    rc;
+ BOOL      fLoadLib = fLoadLibrary;
+
+  if(fDisableUnload) {//only set for kernel32.dll
+	fLoadLib = FALSE;
+  }
+  hinst = hinstance;
+  ret = Win32DllBase::Release();
+  if(ret == 0 && fLoadLib) {
 	//DosFreeModule sends a termination message to the dll.
         //The LX dll informs us when it's removed (UnregisterDll call)
-	hinst = hinstance;
-	delete this;
-	DosFreeModule(hinst);
+	rc = DosFreeModule(hinst);
+	if(rc) {
+		dprintf(("Win32LxDll::Release: DosFreeModule %x returned %d", hinst, rc));
+	}
   }
   return(ret);
Index: trunk/src/kernel32/windlllx.h
===================================================================
--- trunk/src/kernel32/windlllx.h	(revision 3059)
+++ trunk/src/kernel32/windlllx.h	(revision 3059)
@@ -0,0 +1,49 @@
+/* $Id: windlllx.h,v 1.1 2000-03-09 19:03:21 sandervl Exp $ */
+
+/*
+ * Win32 LX Dll class (compiled in OS/2 using Odin32 api)
+ *
+ * Copyright 1999 Sander van Leeuwen (sandervl@xs4all.nl)
+ *
+ *
+ * Project Odin Software License can be found in LICENSE.TXT
+ *
+ */
+#ifndef __WINDLLLX_H__
+#define __WINDLLLX_H__
+
+#include <windllbase.h>
+#include <winimagelx.h>
+
+class Win32LxDll : public Win32LxImage, public Win32DllBase
+{
+public:
+	Win32LxDll(HINSTANCE hInstance, WIN32DLLENTRY DllEntryPoint, PVOID pResData);
+virtual ~Win32LxDll();
+
+#ifdef DEBUG
+virtual	ULONG     AddRef(char *parentname = NULL);
+#else
+virtual ULONG     AddRef();
+#endif
+virtual	ULONG     Release();
+
+	// Loaded by DosLoadModule (only relevant for LX dlls)
+virtual	void      setLoadLibrary() { fLoadLibrary = TRUE; };
+
+	// isLoaded returns TRUE when a dll has been loaded with DosLoadModule
+virtual BOOL      isLoaded()       { return fLoadLibrary; };
+
+	//Should only be called to make sure DosLoadModule is called at least 
+        //once for a dll (to make sure OS/2 doesn't unload the dll when it's
+        //still needed)
+virtual	void      loadLibrary();
+
+virtual BOOL      isLxDll();
+    
+protected:
+
+private:
+};
+
+#endif //__WINDLLLX_H__
Index: trunk/src/kernel32/windllpe2lx.cpp
===================================================================
--- trunk/src/kernel32/windllpe2lx.cpp	(revision 3058)
+++ trunk/src/kernel32/windllpe2lx.cpp	(revision 3059)
@@ -1,3 +1,3 @@
-/* $Id: windllpe2lx.cpp,v 1.6 2000-02-16 14:22:11 sandervl Exp $ */
+/* $Id: windllpe2lx.cpp,v 1.7 2000-03-09 19:03:21 sandervl Exp $ */
 
 /*
@@ -16,5 +16,5 @@
 #define INCL_DOSERRORS      /* DOS Error values */
 #define INCL_DOSMODULEMGR   /* DOS Module management */
-
+#define INCL_DOSSEMAPHORES
 
 /*******************************************************************************
Index: trunk/src/kernel32/winexebase.cpp
===================================================================
--- trunk/src/kernel32/winexebase.cpp	(revision 3058)
+++ trunk/src/kernel32/winexebase.cpp	(revision 3059)
@@ -1,3 +1,3 @@
-/* $Id: winexebase.cpp,v 1.6 2000-03-04 19:52:36 sandervl Exp $ */
+/* $Id: winexebase.cpp,v 1.7 2000-03-09 19:03:21 sandervl Exp $ */
 
 /*
@@ -59,9 +59,33 @@
 Win32ExeBase::~Win32ExeBase()
 {
-  //First delete all dlls that were loaded by the exe or dlls
-  //Then delete all dlls loaded by LoadLibrary (to avoid that we
-  //delete some dlls before the dll, that loaded it, is destroyed)
+ QueueItem    *item;
+ Win32DllBase *dll;
+
+  //First delete all dlls loaded by LoadLibrary 
+  //Then delete all dlls that were loaded by the exe
+  //(NOTE: This is what NT does; first delete loadlib dlls in LIFO order and
+  //       then the exe dlls)
+  Win32DllBase::deleteDynamicLibs();
+
+  dprintf(("Win32ExeBase::~Win32ExeBase"));
+#ifdef DEBUG_ENABLELOG_LEVEL2
+  item = loadedDlls.Head();
+  dll = (Win32DllBase *)loadedDlls.getItem(item);
+  dll->printListOfDlls();
+#endif
+
+  item = loadedDlls.Head();
+  while(item) {
+	dll = (Win32DllBase *)loadedDlls.getItem(item);
+	if(dll == NULL) {
+		dprintf(("ERROR: Win32ExeBase::~Win32ExeBase: dll item == NULL!!"));
+		DebugInt3();
+		break;
+	}
+	dll->Release();
+	item = loadedDlls.getNext(item);
+  }
+
   Win32DllBase::deleteAll();
-  Win32DllBase::deleteAll(TRUE);
 
   WinExe = NULL;
Index: trunk/src/kernel32/winexebase.h
===================================================================
--- trunk/src/kernel32/winexebase.h	(revision 3059)
+++ trunk/src/kernel32/winexebase.h	(revision 3059)
@@ -0,0 +1,46 @@
+/* $Id: winexebase.h,v 1.1 2000-03-09 19:03:22 sandervl Exp $ */
+
+/*
+ * Win32 PE Exe base class
+ *
+ * Copyright 1998-1999 Sander van Leeuwen (sandervl@xs4all.nl)
+ *
+ *
+ * Project Odin Software License can be found in LICENSE.TXT
+ *
+ */
+#ifndef __WINEXEBASE_H__
+#define __WINEXEBASE_H__
+
+#include <winimagebase.h>
+
+typedef ULONG (* WIN32API WIN32EXEENTRY)(LPVOID);
+
+//Base executable class
+class Win32ExeBase : public virtual Win32ImageBase
+{
+public:
+	Win32ExeBase(HINSTANCE hInstance);
+virtual ~Win32ExeBase();
+
+	void   setCommandLine(char *cline);
+	LPSTR  getCommandLineA()                { return cmdLineA;  };
+	LPWSTR getCommandLineW()                { return cmdLineW;  };
+
+	BOOL  isConsoleApp()                   { return fConsoleApp; };
+
+virtual ULONG start();
+
+virtual BOOL  isDll();
+	
+protected:
+	LPSTR  cmdLineA;
+	LPWSTR cmdLineW;
+	BOOL   fConsoleApp;
+
+private:
+};
+
+extern Win32ExeBase *WinExe;
+
+#endif //__WINEXEBASE_H__
Index: trunk/src/kernel32/winexepe2lx.cpp
===================================================================
--- trunk/src/kernel32/winexepe2lx.cpp	(revision 3058)
+++ trunk/src/kernel32/winexepe2lx.cpp	(revision 3059)
@@ -1,3 +1,3 @@
-/* $Id: winexepe2lx.cpp,v 1.4 2000-02-16 14:22:11 sandervl Exp $ */
+/* $Id: winexepe2lx.cpp,v 1.5 2000-03-09 19:03:22 sandervl Exp $ */
 
 /*
@@ -37,4 +37,6 @@
 
 
+BOOL fPe2Lx = FALSE;
+
 /**
  * Register a Pe2Lx Executable module.
@@ -56,4 +58,6 @@
 {
     Win32Pe2LxExe *pWinPe2LxExe;
+
+    fPe2Lx = TRUE;
 
     /* I/O init. */
Index: trunk/src/kernel32/winexepe2lx.h
===================================================================
--- trunk/src/kernel32/winexepe2lx.h	(revision 3059)
+++ trunk/src/kernel32/winexepe2lx.h	(revision 3059)
@@ -0,0 +1,36 @@
+/* $Id: winexepe2lx.h,v 1.1 2000-03-09 19:03:22 sandervl Exp $ */
+
+/*
+ * Win32 PE2LX Exe class
+ *
+ * Copyright 1999 Sander van Leeuwen (sandervl@xs4all.nl)
+ * Copyright 1999 knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
+ *
+ * Project Odin Software License can be found in LICENSE.TXT
+ *
+ */
+#ifndef __WINEXEPE2LX_H__
+#define __WINEXEPE2LX_H__
+
+#include <winexebase.h>
+#include <winimagepe2lx.h>
+
+
+/**
+ * Class for executables converted by pe2lx or win32k
+ * @shortdesc   Class for executables converted by pe2lx or win32k
+ * @author      Sander van Leeuwen, knut st. osmundsen
+ * @approval    -
+ */
+class Win32Pe2LxExe : public Win32Pe2LxImage, public Win32ExeBase
+{
+public:
+    /** @cat Constructor/Destructor */
+    Win32Pe2LxExe(HINSTANCE hinstance, BOOL fWin32k);
+    virtual ~Win32Pe2LxExe();
+    BOOL init();
+};
+
+extern BOOL fPe2Lx;
+
+#endif //__WINEXEPE2LX_H__
Index: trunk/src/kernel32/winimagebase.cpp
===================================================================
--- trunk/src/kernel32/winimagebase.cpp	(revision 3058)
+++ trunk/src/kernel32/winimagebase.cpp	(revision 3059)
@@ -1,3 +1,3 @@
-/* $Id: winimagebase.cpp,v 1.9 2000-02-22 19:12:53 sandervl Exp $ */
+/* $Id: winimagebase.cpp,v 1.10 2000-03-09 19:03:22 sandervl Exp $ */
 
 /*
@@ -98,4 +98,30 @@
 }
 //******************************************************************************
+//Add image to dependency list of this image
+//******************************************************************************
+void Win32ImageBase::addDependency(Win32DllBase *image)
+{
+  loadedDlls.Push((ULONG)image);
+}
+//******************************************************************************
+//******************************************************************************
+BOOL Win32ImageBase::dependsOn(Win32DllBase *image)
+{
+ QueueItem    *item;
+ BOOL          ret = FALSE;
+
+  dlllistmutex.enter();
+  item = loadedDlls.Head();
+  while(item) {
+	if(loadedDlls.getItem(item) == (ULONG)image) {
+		ret = TRUE;
+		break;
+	}	  
+	item = loadedDlls.getNext(item);
+  }
+  dlllistmutex.leave();
+  return ret;
+}
+//******************************************************************************
 //Returns required OS version for this image
 //******************************************************************************
Index: trunk/src/kernel32/winimagebase.h
===================================================================
--- trunk/src/kernel32/winimagebase.h	(revision 3059)
+++ trunk/src/kernel32/winimagebase.h	(revision 3059)
@@ -0,0 +1,164 @@
+/* $Id: winimagebase.h,v 1.1 2000-03-09 19:03:22 sandervl Exp $ */
+
+/*
+ * Win32 PE Image base class
+ *
+ * Copyright 1998-1999 Sander van Leeuwen (sandervl@xs4all.nl)
+ *
+ *
+ * Project Odin Software License can be found in LICENSE.TXT
+ *
+ */
+#ifndef __WINIMAGEBASE_H__
+#define __WINIMAGEBASE_H__
+
+#include <peexe.h>
+#include "queue.h"
+
+#define MAGIC_WINIMAGE          0x11223344
+
+#ifndef CCHMAXPATH
+#define CCHMAXPATH 260
+#endif
+
+#define LANG_GETFIRST           0x80000000
+#define ID_GETFIRST             LANG_GETFIRST
+#define IDLANG_GETFIRST         LANG_GETFIRST
+
+#ifndef ENUMRESNAMEPROC
+    typedef BOOL (* CALLBACK ENUMRESTYPEPROCA)(HMODULE,LPSTR,LONG);
+    typedef BOOL (* CALLBACK ENUMRESTYPEPROCW)(HMODULE,LPWSTR,LONG);
+    typedef BOOL (* CALLBACK ENUMRESNAMEPROCA)(HMODULE,LPCSTR,LPSTR,LONG);
+    typedef BOOL (* CALLBACK ENUMRESNAMEPROCW)(HMODULE,LPCWSTR,LPWSTR,LONG);
+    typedef BOOL (* CALLBACK ENUMRESLANGPROCA)(HMODULE,LPCSTR,LPCSTR,WORD,LONG);
+    typedef BOOL (* CALLBACK ENUMRESLANGPROCW)(HMODULE,LPCWSTR,LPCWSTR,WORD,LONG);
+#endif
+
+class Win32Resource;
+class Win32DllBase;
+
+class Win32ImageBase
+{
+protected:
+        DWORD magic;
+public:
+        void checkObject()
+        {
+                if(magic != MAGIC_WINIMAGE) {
+                        eprintf(("Corrupt this pointer %X %X!!", this, magic));
+                        DebugInt3();
+                }
+        };
+
+public:
+         // Constructors and destructors
+         Win32ImageBase(HINSTANCE hInstance);
+virtual ~Win32ImageBase();
+
+        ULONG     getError()          { return errorState; };
+        HINSTANCE getInstanceHandle() { return hinstance; };
+
+//Returns required OS version for this image
+virtual ULONG     getVersion();
+
+virtual void setFullPath(char *name);
+        char *getFullPath()           { return fullpath; };
+
+	char *getModuleName()	      { return szModule; };
+
+virtual HRSRC findResourceA(LPCSTR lpszName, LPSTR lpszType, ULONG lang = LANG_GETFIRST);
+        HRSRC findResourceW(LPWSTR lpszName, LPWSTR lpszType, ULONG lang = LANG_GETFIRST);
+virtual ULONG getResourceSizeA(LPCSTR lpszName, LPSTR lpszType, ULONG lang = LANG_GETFIRST);
+        ULONG getResourceSizeW(LPCWSTR lpszName, LPWSTR lpszType, ULONG lang = LANG_GETFIRST);
+virtual BOOL  enumResourceNamesA(HMODULE hmod, LPCTSTR  lpszType, ENUMRESNAMEPROCA lpEnumFunc, LONG lParam);
+virtual BOOL  enumResourceNamesW(HMODULE hmod, LPCWSTR  lpszType, ENUMRESNAMEPROCW lpEnumFunc, LONG lParam);
+virtual BOOL  enumResourceTypesA(HMODULE hmod, ENUMRESTYPEPROCA lpEnumFunc, 
+                                 LONG lParam);
+virtual BOOL  enumResourceTypesW(HMODULE hmod, ENUMRESTYPEPROCW lpEnumFunc, 
+                                 LONG lParam);
+
+virtual ULONG getVersionSize();
+virtual BOOL  getVersionStruct(char *verstruct, ULONG bufLength);
+
+static  BOOL  isPEImage(char *szFileName);
+
+	void  setEntryPoint(ULONG startAddress) { entryPoint = startAddress; };
+
+        void  setTLSAddress(LPVOID dwTlsAddress)     	{ tlsAddress = dwTlsAddress; };
+        void  setTLSIndexAddr(LPDWORD dwTlsIndexAddr)	{ tlsIndexAddr = dwTlsIndexAddr; };
+        void  setTLSInitSize(ULONG dwTlsSize)		{ tlsInitSize = dwTlsSize; };
+        void  setTLSTotalSize(ULONG dwTlsSize)		{ tlsTotalSize = dwTlsSize; };
+        void  setTLSCallBackAddr(PIMAGE_TLS_CALLBACK *dwTlsCallBackAddr)
+	{
+	   tlsCallBackAddr = dwTlsCallBackAddr;
+	};
+
+	void  tlsAttachThread();	//setup TLS structures for new thread
+	void  tlsDetachThread();	//destroy TLS structures
+
+virtual	ULONG     getApi(char *name)  = 0;
+virtual ULONG     getApi(int ordinal) = 0;
+
+virtual BOOL  isDll() = 0;
+
+static Win32ImageBase * findModule(HMODULE hModule);
+
+	//Add image to dependency list of this image
+	void  addDependency(Win32DllBase *dll);
+        BOOL  dependsOn(Win32DllBase *dll);
+
+protected:
+	void tlsAlloc();		//Allocate TLS index for this module
+	void tlsDelete();		//Destroy TLS index for this module
+
+        Win32Resource        *winres;
+
+        ULONG                 errorState, entryPoint;
+
+        char                 *fullpath;
+	char      	      szModule[CCHMAXPATH];
+	char                  szFileName[CCHMAXPATH];
+
+        HINSTANCE             hinstance;
+
+  	LPVOID 	              tlsAddress;		//address of TLS data
+  	LPDWORD		      tlsIndexAddr;		//address of DWORD that receives the TLS index
+  	ULONG 		      tlsInitSize;		//size of initialized TLS memory block
+  	ULONG 		      tlsTotalSize;		//size of TLS memory block
+  	PIMAGE_TLS_CALLBACK  *tlsCallBackAddr;	//ptr to TLS callback array
+	ULONG                 tlsIndex;		//module TLS index
+
+        ULONG getPEResourceSize(ULONG id, ULONG type, ULONG lang = LANG_GETFIRST);
+
+        PIMAGE_RESOURCE_DATA_ENTRY getPEResourceEntry(ULONG id, ULONG type, ULONG lang = LANG_GETFIRST);
+        PIMAGE_RESOURCE_DATA_ENTRY ProcessResSubDir(PIMAGE_RESOURCE_DIRECTORY prdType,
+                                                    ULONG *nodeData, int level);
+        PIMAGE_RESOURCE_DIRECTORY  getResSubDirW(PIMAGE_RESOURCE_DIRECTORY pResDir, LPCWSTR lpszName);
+        PIMAGE_RESOURCE_DIRECTORY  getResSubDirA(PIMAGE_RESOURCE_DIRECTORY pResDir, LPCTSTR lpszName);
+
+        PIMAGE_RESOURCE_DIRECTORY pResDir;
+
+        //substracted from RVA data offsets
+        ULONG                     ulRVAResourceSection;
+
+	//linked list of dlls loaded on behalf of this executable image (dll or exe)
+        Queue         		   loadedDlls;
+private:
+
+        friend class Win32Resource;
+        friend ULONG SYSTEM GetVersionSize(char *modname);
+};
+
+//SvL: This structure is placed at the end of the first page of the image (header
+//     page), so we can determine the Win32Image pointer from a HINSTANCE variable
+//     (which is actually the address of the win32 module)
+typedef struct
+{
+  ULONG           magic1;
+  Win32ImageBase *image;
+  ULONG           magic2;
+} WINIMAGE_LOOKUP;
+
+#define WINIMAGE_LOOKUPADDR(a)	(WINIMAGE_LOOKUP *)((ULONG)a + PAGE_SIZE - sizeof(WINIMAGE_LOOKUP))
+
+#endif //__WINIMAGEBASE_H__
Index: trunk/src/kernel32/winimagepeldr.cpp
===================================================================
--- trunk/src/kernel32/winimagepeldr.cpp	(revision 3058)
+++ trunk/src/kernel32/winimagepeldr.cpp	(revision 3059)
@@ -1,3 +1,3 @@
-/* $Id: winimagepeldr.cpp,v 1.34 2000-03-04 19:52:36 sandervl Exp $ */
+/* $Id: winimagepeldr.cpp,v 1.35 2000-03-09 19:03:22 sandervl Exp $ */
 
 /*
@@ -37,7 +37,7 @@
 #include <misc.h>
 #include <win32api.h>
-#include <winimagebase.h>
-#include <winimagepeldr.h>
-#include <windllpeldr.h>
+#include "winimagebase.h"
+#include "winimagepeldr.h"
+#include "windllpeldr.h"
 #include <pefile.h>
 #include <unicode.h>
@@ -1389,4 +1389,7 @@
 			return(FALSE);
 		}
+		//Mark this dll as loaded by DosLoadModule
+  		WinDll->setLoadLibrary();
+		WinDll->AddRef();
 	}
 	else {
@@ -1406,17 +1409,40 @@
 	            return(FALSE);
 	        }
+#ifdef DEBUG
+    		WinDll->AddRef(getModuleName());
+#else
+    		WinDll->AddRef();
+#endif
 	        if(WinDll->attachProcess() == FALSE) {
         	    dprintf((LOG, "attachProcess failed!" ));
+		    delete WinDll;
 	            errorState = ERROR_INTERNAL;
 	            return(FALSE);
 	        }
 	}
+
 	dprintf((LOG, "**********************************************************************" ));
 	dprintf((LOG, "**********************  Finished Loading Module  *********************" ));
         dprintf((LOG, "**********************************************************************" ));
     }
-    else    dprintf((LOG, "Already found ", pszCurModule ));
-
-    WinDll->AddRef();
+    else {
+	if(WinDll->isLxDll() && !WinDll->isLoaded()) {
+		//can happen with i.e. wininet
+		//wininet depends on wsock32; when the app loads wsock32 afterwards
+	  	//with LoadLibrary or as a child of another dll, we need to make
+                //sure it's loaded once with DosLoadModule
+		WinDll->loadLibrary();
+	}
+	WinDll->AddRef();
+	
+	dprintf((LOG, "Already found ", pszCurModule));
+    }
+    //add the dll we just loaded to dependency list for this image
+    addDependency((Win32DllBase *)WinDll);
+
+    //Make sure the dependency list is correct (already done
+    //in the ctor of Win32DllBase, but for LX dlls the parent is
+    //then set to NULL; so change it here again
+    WinDll->setUnloadOrder(this);
 
     pulImport  = (PULONG)((ULONG)pulImport + (ULONG)win32file);
Index: trunk/src/kernel32/wprocess.cpp
===================================================================
--- trunk/src/kernel32/wprocess.cpp	(revision 3058)
+++ trunk/src/kernel32/wprocess.cpp	(revision 3059)
@@ -1,3 +1,3 @@
-/* $Id: wprocess.cpp,v 1.71 2000-03-04 19:52:37 sandervl Exp $ */
+/* $Id: wprocess.cpp,v 1.72 2000-03-09 19:03:23 sandervl Exp $ */
 
 /*
@@ -20,8 +20,9 @@
 
 #include <unicode.h>
-#include <windllbase.h>
-#include <winexebase.h>
-#include <windllpeldr.h>
-#include <winfakepeldr.h>
+#include "windllbase.h"
+#include "winexebase.h"
+#include "windllpeldr.h"
+#include "winexepe2lx.h"
+#include "winfakepeldr.h"
 #include <vmutex.h>
 
@@ -382,5 +383,16 @@
   if(winmod) {
   	dprintf(("FreeLibrary %s", winmod->getName()));
-        winmod->Release();
+	//Only free it when the nrDynamicLibRef != 0
+	//This prevent problems after ExitProcess:
+	//i.e. dll A is referenced by our exe and loaded with LoadLibrary by dll B
+	//     During ExitProcess it's unloaded once (before dll B), dll B calls
+        //     FreeLibrary, but our exe also has a reference -> unloaded too many times
+	if(winmod->isDynamicLib()) {
+        	winmod->decDynamicLib();
+        	winmod->Release();
+	}
+	else {
+		dprintf(("Skipping dynamic unload as nrDynamicLibRef == 0"));
+	}
         return(TRUE);
   }
@@ -404,6 +416,14 @@
   module = Win32DllBase::findModule((LPSTR)lpszLibFile);
   if(module) {
+	if(module->isLxDll() && !module->isLoaded() && !fPe2Lx) {
+		//can happen with i.e. wininet
+		//wininet depends on wsock32; when the app loads wsock32 afterwards
+	  	//with LoadLibrary or as a child of another dll, we need to make
+                //sure it's loaded once with DosLoadModule
+		module->setLoadLibrary();
+	}
+	module->incDynamicLib();
         module->AddRef();
-    dprintf(("iLoadLibrary: found %s -> handle %x", lpszLibFile, module->getInstanceHandle()));
+    	dprintf(("iLoadLibrary: found %s -> handle %x", lpszLibFile, module->getInstanceHandle()));
         return module->getInstanceHandle();
   }
@@ -421,9 +441,17 @@
   if(hDll)
   {
-    return hDll;    //converted dll or win32k took care of it
+  	module = Win32DllBase::findModule(hDll);
+  	if(module && module->isLxDll() && !fPe2Lx) {
+		module->setLoadLibrary();
+		module->AddRef();
+	}
+	if(module)
+		module->incDynamicLib();
+	//system dll, converted dll or win32k took care of it
+	return hDll;
   }
 
   if(!strstr(modname, ".")) {
-    strcat(modname,".DLL");
+    	strcat(modname,".DLL");
   }
 
@@ -432,4 +460,5 @@
         module = Win32DllBase::findModule((char *)modname);
         if(module) {//don't load it again
+  	    module->incDynamicLib();
             module->AddRef();
             return module->getInstanceHandle();
@@ -449,8 +478,6 @@
             peldrDll->setNoEntryCalls();
         }
-	//Set flag so this dll doesn't get automatically deleted in ExitProcess
-        //(the first time); give application the chance to free it first
-	//If it's not freed, we delete it the 2nd time in ExitProcess
-	peldrDll->SetDynamicallyLoaded();
+        peldrDll->incDynamicLib();
+        peldrDll->AddRef();
 
         if(peldrDll->attachProcess() == FALSE) {
@@ -459,5 +486,4 @@
             return(0);
         }
-        peldrDll->AddRef();
         return peldrDll->getInstanceHandle();
   }
