Bugfix: Call DllEntryPoint for *every* process that loads the DLL, not
just for the first one.
Bypass 32->16->32 transition when calling DllEntryPoint of built-in.

diff --git a/loader/ne/segment.c b/loader/ne/segment.c
index af59970..dbc004a 100644
--- a/loader/ne/segment.c
+++ b/loader/ne/segment.c
@@ -25,6 +25,7 @@
 #include "file.h"
 #include "module.h"
 #include "stackframe.h"
+#include "builtin16.h"
 #include "debugtools.h"
 #include "xmalloc.h"
 #include "toolhelp.h"
@@ -614,50 +615,6 @@
 }
 
 /***********************************************************************
- *           NE_CallDllEntryPoint
- *
- * Call the DllEntryPoint of DLLs with subsystem >= 4.0 
- */
-
-static void NE_CallDllEntryPoint( NE_MODULE *pModule, DWORD dwReason )
-{
-    WORD hInst, ds, heap;
-    FARPROC16 entryPoint;
-    WORD ordinal;
-    CONTEXT86 context;
-    LPBYTE stack = (LPBYTE)CURRENT_STACK16;
-
-    if (!(pModule->flags & NE_FFLAGS_BUILTIN) && pModule->expected_version < 0x0400) return;
-    if (!(ordinal = NE_GetOrdinal( pModule->self, "DllEntryPoint" ))) return;
-    if (!(entryPoint = NE_GetEntryPoint( pModule->self, ordinal ))) return;
-
-    memset( &context, 0, sizeof(context) );
-
-    NE_GetDLLInitParams( pModule, &hInst, &ds, &heap );
-
-    DS_reg(&context) = ds;
-    ES_reg(&context) = ds;   /* who knows ... */
-
-    CS_reg(&context) = HIWORD(entryPoint);
-    EIP_reg(&context) = LOWORD(entryPoint);
-    EBP_reg(&context) =  OFFSETOF( NtCurrentTeb()->cur_stack )
-                         + (WORD)&((STACK16FRAME*)0)->bp;
-
-    *(DWORD *)(stack -  4) = dwReason;      /* dwReason */
-    *(WORD *) (stack -  6) = hInst;         /* hInst */
-    *(WORD *) (stack -  8) = ds;            /* wDS */
-    *(WORD *) (stack - 10) = heap;          /* wHeapSize */
-    *(DWORD *)(stack - 14) = 0;             /* dwReserved1 */
-    *(WORD *) (stack - 16) = 0;             /* wReserved2 */
-
-    TRACE_(dll)("Calling DllEntryPoint, cs:ip=%04lx:%04lx\n",
-          CS_reg(&context), EIP_reg(&context));
-
-    Callbacks->CallRegisterShortProc( &context, 16 );
-}
-
-
-/***********************************************************************
  *           NE_InitializeDLLs
  *
  * Recursively initialize all DLLs (according to the order in which 
@@ -683,7 +640,116 @@
         GlobalFree16( to_init );
     }
     NE_InitDLL( pTask, pModule );
+}
+
+
+/***********************************************************************
+ *           NE_CallDllEntryPoint
+ *
+ * Call the DllEntryPoint of DLLs with subsystem >= 4.0 
+ */
+
+static void NE_CallDllEntryPoint( NE_MODULE *pModule, DWORD dwReason )
+{
+    WORD hInst, ds, heap;
+    FARPROC16 entryPoint;
+    WORD ordinal;
+
+    if (!(pModule->flags & NE_FFLAGS_LIBMODULE)) return;
+    if (!(pModule->flags & NE_FFLAGS_BUILTIN) && pModule->expected_version < 0x0400) return;
+    if (!(ordinal = NE_GetOrdinal( pModule->self, "DllEntryPoint" ))) return;
+    if (!(entryPoint = NE_GetEntryPoint( pModule->self, ordinal ))) return;
+
+    NE_GetDLLInitParams( pModule, &hInst, &ds, &heap );
+
+    TRACE_(dll)( "Calling %s DllEntryPoint, cs:ip=%04x:%04x\n",
+                 NE_MODULE_NAME( pModule ),
+                 SELECTOROF(entryPoint), OFFSETOF(entryPoint) );
+
+    if ( pModule->flags & NE_FFLAGS_BUILTIN )
+    {
+        DWORD WINAPI (*entryProc)(DWORD,WORD,WORD,WORD,DWORD,WORD) =
+              (DWORD WINAPI (*)(DWORD,WORD,WORD,WORD,DWORD,WORD))
+              ((ENTRYPOINT16 *)PTR_SEG_TO_LIN( entryPoint ))->target;
+
+        entryProc( dwReason, hInst, ds, heap, 0, 0 );
+    }
+    else
+    {
+        LPBYTE stack = (LPBYTE)CURRENT_STACK16;
+        CONTEXT86 context;
+
+        memset( &context, 0, sizeof(context) );
+        DS_reg(&context) = ds;
+        ES_reg(&context) = ds;   /* who knows ... */
+
+        CS_reg(&context) = HIWORD(entryPoint);
+        EIP_reg(&context) = LOWORD(entryPoint);
+        EBP_reg(&context) =  OFFSETOF( NtCurrentTeb()->cur_stack )
+                             + (WORD)&((STACK16FRAME*)0)->bp;
+
+        *(DWORD *)(stack -  4) = dwReason;      /* dwReason */
+        *(WORD *) (stack -  6) = hInst;         /* hInst */
+        *(WORD *) (stack -  8) = ds;            /* wDS */
+        *(WORD *) (stack - 10) = heap;          /* wHeapSize */
+        *(DWORD *)(stack - 14) = 0;             /* dwReserved1 */
+        *(WORD *) (stack - 16) = 0;             /* wReserved2 */
+
+        Callbacks->CallRegisterShortProc( &context, 16 );
+    }
+}
+
+/***********************************************************************
+ *           NE_DllProcessAttach
+ * 
+ * Call the DllEntryPoint of all modules this one (recursively)
+ * depends on, according to the order in which they were loaded.
+ *
+ * Note that --as opposed to the PE module case-- there is no notion
+ * of 'module loaded into a process' for NE modules, and hence we 
+ * have no place to store the fact that the DllEntryPoint of a
+ * given module was already called on behalf of this process (e.g.
+ * due to some earlier LoadLibrary16 call).
+ *
+ * Thus, we just call the DllEntryPoint twice in that case.  Win9x
+ * appears to behave this way as well ...
+ *
+ * This routine must only be called with the Win16Lock held.
+ * 
+ * FIXME:  We should actually abort loading in case the DllEntryPoint
+ *         returns FALSE ...
+ *
+ */
+void NE_DllProcessAttach( HMODULE16 hModule )
+{
+    NE_MODULE *pModule;
+    WORD *pModRef;
+    int i;
+
+    if (!(pModule = NE_GetPtr( hModule ))) return;
+    assert( !(pModule->flags & NE_FFLAGS_WIN32) );
+
+    /* Check for recursive call */
+    if ( pModule->misc_flags & 0x80 ) return;
+
+    TRACE_(dll)("(%s) - START\n", NE_MODULE_NAME(pModule) );
+
+    /* Tag current module to prevent recursive loop */
+    pModule->misc_flags |= 0x80;
+
+    /* Recursively attach all DLLs this one depends on */
+    pModRef = NE_MODULE_TABLE( pModule );
+    for ( i = 0; i < pModule->modref_count; i++ )
+        if ( pModRef[i] )
+            NE_DllProcessAttach( (HMODULE16)pModRef[i] );
+
+    /* Call DLL entry point */
     NE_CallDllEntryPoint( pModule, DLL_PROCESS_ATTACH );
+
+    /* Remove recursion flag */
+    pModule->misc_flags &= ~0x80;
+
+    TRACE_(dll)("(%s) - END\n", NE_MODULE_NAME(pModule) );
 }