Index: trunk/src/VBox/Runtime/r3/win/nocrt-startup-common-win.cpp
===================================================================
--- trunk/src/VBox/Runtime/r3/win/nocrt-startup-common-win.cpp	(revision 95870)
+++ trunk/src/VBox/Runtime/r3/win/nocrt-startup-common-win.cpp	(revision 95870)
@@ -0,0 +1,78 @@
+/* $Id$ */
+/** @file
+ * IPRT - No-CRT - Common Windows startup code.
+ */
+
+/*
+ * Copyright (C) 2006-2022 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+*   Header Files                                                                                                                 *
+*********************************************************************************************************************************/
+#include "internal/iprt.h"
+#include "internal/process.h"
+
+#include <iprt/nt/nt-and-windows.h>
+#include <iprt/getopt.h>
+#include <iprt/message.h>
+#include <iprt/path.h>
+#include <iprt/string.h>
+#include <iprt/utf16.h>
+
+#include "internal/compiler-vcc.h"
+
+
+/*********************************************************************************************************************************
+*   Global Variables                                                                                                             *
+*********************************************************************************************************************************/
+RT_C_DECLS_BEGIN
+DECL_HIDDEN_DATA(char)      g_szrtProcExePath[RTPATH_MAX] = "Unknown.exe";
+DECL_HIDDEN_DATA(size_t)    g_cchrtProcExePath = 11;
+DECL_HIDDEN_DATA(size_t)    g_cchrtProcExeDir = 0;
+DECL_HIDDEN_DATA(size_t)    g_offrtProcName = 0;
+RT_C_DECLS_END
+
+
+
+void rtVccWinInitProcExecPath(void)
+{
+    WCHAR wszPath[RTPATH_MAX];
+    UINT cwcPath = GetModuleFileNameW(NULL, wszPath, RT_ELEMENTS(wszPath));
+    if (cwcPath)
+    {
+        char *pszDst = g_szrtProcExePath;
+        int rc = RTUtf16ToUtf8Ex(wszPath, cwcPath, &pszDst, sizeof(g_szrtProcExePath), &g_cchrtProcExePath);
+        if (RT_SUCCESS(rc))
+        {
+            g_cchrtProcExeDir = g_offrtProcName = RTPathFilename(pszDst) - g_szrtProcExePath;
+            while (   g_cchrtProcExeDir >= 2
+                   && RTPATH_IS_SLASH(g_szrtProcExePath[g_cchrtProcExeDir - 1])
+                   && g_szrtProcExePath[g_cchrtProcExeDir - 2] != ':')
+                g_cchrtProcExeDir--;
+        }
+        else
+            RTMsgError("initProcExecPath: RTUtf16ToUtf8Ex failed: %Rrc\n", rc);
+    }
+    else
+        RTMsgError("initProcExecPath: GetModuleFileNameW failed: %Rhrc\n", GetLastError());
+}
+
Index: trunk/src/VBox/Runtime/r3/win/nocrt-startup-dll-win.cpp
===================================================================
--- trunk/src/VBox/Runtime/r3/win/nocrt-startup-dll-win.cpp	(revision 95870)
+++ trunk/src/VBox/Runtime/r3/win/nocrt-startup-dll-win.cpp	(revision 95870)
@@ -0,0 +1,153 @@
+/* $Id$ */
+/** @file
+ * IPRT - No-CRT - Windows EXE startup code.
+ *
+ * @note Does not run static constructors and destructors!
+ */
+
+/*
+ * Copyright (C) 2006-2022 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+*   Header Files                                                                                                                 *
+*********************************************************************************************************************************/
+#include "internal/iprt.h"
+#include "internal/process.h"
+
+#include <iprt/nt/nt-and-windows.h>
+#include <iprt/getopt.h>
+#include <iprt/message.h>
+#include <iprt/path.h>
+#include <iprt/string.h>
+#include <iprt/utf16.h>
+
+#ifdef IPRT_NO_CRT
+# include <iprt/asm.h>
+# include <iprt/nocrt/stdlib.h>
+#endif
+
+#include "internal/compiler-vcc.h"
+
+
+/*********************************************************************************************************************************
+*   Global Variables                                                                                                             *
+*********************************************************************************************************************************/
+static volatile int32_t g_cAttached = 0;
+
+
+/*********************************************************************************************************************************
+*   Internal Functions                                                                                                           *
+*********************************************************************************************************************************/
+extern DECLHIDDEN(void) InitStdHandles(PRTL_USER_PROCESS_PARAMETERS pParams); /* nocrt-streams-win.cpp */ /** @todo put in header */
+
+extern "C" BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID pvReserved);
+
+
+DECL_NO_INLINE(static, BOOL) rtVccDllMainForward(HINSTANCE hInstance, DWORD dwReason, LPVOID pvReserved)
+{
+    return DllMain(hInstance, dwReason, pvReserved);
+}
+
+
+
+DECL_NO_INLINE(static, BOOL) rtVccDllMainProcessAttach(HINSTANCE hInstance, LPVOID pvReserved)
+{
+    /*
+     * Initialize the CRT the first time thru.
+     */
+    if (g_cAttached == 0)
+    {
+        PPEB pPeb = RTNtCurrentPeb();
+        InitStdHandles(pPeb->ProcessParameters);
+        rtVccWinInitProcExecPath();
+
+        int rc = rtVccInitializersRunInit();
+        if (RT_FAILURE(rc))
+            return FALSE;
+    }
+    g_cAttached++;
+
+    /*
+     * Call the DllMain function.
+     */
+    BOOL fRet = rtVccDllMainForward(hInstance, DLL_PROCESS_ATTACH, pvReserved);
+
+    /*
+     * On failure, we call the DllMain function again, decrement the init counter
+     * and probably run termination callbacks.
+     */
+    if (!fRet)
+    {
+        rtVccDllMainForward(hInstance, DLL_PROCESS_DETACH, pvReserved);
+        if (--g_cAttached == 0)
+        {
+            rtVccTermRunAtExit();
+            rtVccInitializersRunTerm();
+        }
+    }
+    return fRet;
+}
+
+
+DECL_NO_INLINE(static, BOOL) rtVccDllMainProcessDetach(HINSTANCE hInstance, LPVOID pvReserved)
+{
+    /*
+     * Make sure there isn't an imbalance before calling DllMain and shutting
+     * down our own internals.
+     */
+    if (g_cAttached <= 0)
+        return FALSE;
+
+    /*
+     * Call DllMain.
+     */
+    BOOL fRet = rtVccDllMainForward(hInstance, DLL_PROCESS_DETACH, pvReserved);
+
+    /*
+     * Work g_cAttached and probably do uninitialization.  We'll do this regardless
+     * of what DllMain returned.
+     */
+    if (--g_cAttached == 0)
+    {
+        rtVccTermRunAtExit();
+        rtVccInitializersRunTerm();
+    }
+    return fRet;
+}
+
+
+extern "C" BOOL WINAPI _DllMainCRTStartup(HINSTANCE hInstance, DWORD dwReason, LPVOID pvReserved)
+{
+    switch (dwReason)
+    {
+        case DLL_PROCESS_ATTACH:
+            rtVccInitSecurityCookie(); /* This function must be minimal because of this! */
+            return rtVccDllMainProcessAttach(hInstance, pvReserved);
+
+        case DLL_PROCESS_DETACH:
+            return rtVccDllMainProcessDetach(hInstance, pvReserved);
+
+        default:
+            return rtVccDllMainForward(hInstance, dwReason, pvReserved);
+    }
+}
+
Index: trunk/src/VBox/Runtime/r3/win/nocrt-startup-exe-win.cpp
===================================================================
--- trunk/src/VBox/Runtime/r3/win/nocrt-startup-exe-win.cpp	(revision 95861)
+++ trunk/src/VBox/Runtime/r3/win/nocrt-startup-exe-win.cpp	(revision 95870)
@@ -41,41 +41,5 @@
 #include <iprt/utf16.h>
 
-#ifdef IPRT_NO_CRT
-# include <iprt/asm.h>
-# include <iprt/nocrt/stdlib.h>
-#endif
-
 #include "internal/compiler-vcc.h"
-
-
-/*********************************************************************************************************************************
-*   Structures and Typedefs                                                                                                      *
-*********************************************************************************************************************************/
-#ifdef IPRT_NO_CRT
-typedef struct RTNOCRTATEXITCHUNK
-{
-    PFNRTNOCRTATEXITCALLBACK apfnCallbacks[256];
-} RTNOCRTATEXITCHUNK;
-#endif
-
-
-/*********************************************************************************************************************************
-*   Global Variables                                                                                                             *
-*********************************************************************************************************************************/
-RT_C_DECLS_BEGIN
-DECL_HIDDEN_DATA(char)      g_szrtProcExePath[RTPATH_MAX] = "Unknown.exe";
-DECL_HIDDEN_DATA(size_t)    g_cchrtProcExePath = 11;
-DECL_HIDDEN_DATA(size_t)    g_cchrtProcExeDir = 0;
-DECL_HIDDEN_DATA(size_t)    g_offrtProcName = 0;
-RT_C_DECLS_END
-
-#ifdef IPRT_NO_CRT
-/** The first atexit() registration chunk. */
-static RTNOCRTATEXITCHUNK   g_aAtExitPrealloc;
-/** Array of atexit() callback chunk pointers. */
-static RTNOCRTATEXITCHUNK  *g_apAtExit[8192 / 256] = { &g_aAtExitPrealloc, };
-/** Chunk and callback index in one. */
-static volatile uint32_t    g_idxNextAtExit        = 0;
-#endif
 
 
@@ -88,45 +52,4 @@
 
 
-#ifdef IPRT_NO_CRT
-extern "C"
-int rtnocrt_atexit(PFNRTNOCRTATEXITCALLBACK pfnCallback) RT_NOEXCEPT
-{
-    AssertPtr(pfnCallback);
-
-    /*
-     * Allocate a table index.
-     */
-    uint32_t idx = ASMAtomicIncU32(&g_idxNextAtExit) - 1;
-    AssertReturnStmt(idx < RT_ELEMENTS(g_apAtExit) * RT_ELEMENTS(g_apAtExit[0]->apfnCallbacks),
-                     ASMAtomicDecU32(&g_idxNextAtExit), -1);
-
-    /*
-     * Make sure the table chunk is there.
-     */
-    uint32_t            idxChunk = idx / RT_ELEMENTS(g_apAtExit[0]->apfnCallbacks);
-    RTNOCRTATEXITCHUNK *pChunk   = ASMAtomicReadPtrT(&g_apAtExit[idxChunk], RTNOCRTATEXITCHUNK *);
-    if (!pChunk)
-    {
-        pChunk = (RTNOCRTATEXITCHUNK *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*pChunk));
-        AssertReturn(pChunk, -1); /* don't try decrement, someone could be racing us... */
-
-        if (!ASMAtomicCmpXchgPtr(&g_apAtExit[idxChunk], pChunk, NULL))
-        {
-            HeapFree(GetProcessHeap(), 0, pChunk);
-
-            pChunk = ASMAtomicReadPtrT(&g_apAtExit[idxChunk], RTNOCRTATEXITCHUNK *);
-            Assert(pChunk);
-        }
-    }
-
-    /*
-     * Add our callback.
-     */
-    pChunk->apfnCallbacks[idxChunk % RT_ELEMENTS(pChunk->apfnCallbacks)] = pfnCallback;
-    return 0;
-}
-#endif
-
-
 static int rtTerminateProcess(int32_t rcExit, bool fDoAtExit)
 {
@@ -137,28 +60,5 @@
     if (fDoAtExit)
     {
-        uint32_t idxAtExit = ASMAtomicReadU32(&g_idxNextAtExit);
-        if (idxAtExit-- > 0)
-        {
-            uint32_t idxChunk    = idxAtExit / RT_ELEMENTS(g_apAtExit[0]->apfnCallbacks);
-            uint32_t idxCallback = idxAtExit % RT_ELEMENTS(g_apAtExit[0]->apfnCallbacks);
-            for (;;)
-            {
-                RTNOCRTATEXITCHUNK *pChunk = ASMAtomicReadPtrT(&g_apAtExit[idxChunk], RTNOCRTATEXITCHUNK *);
-                if (pChunk)
-                {
-                    do
-                    {
-                        PFNRTNOCRTATEXITCALLBACK pfnCallback = pChunk->apfnCallbacks[idxCallback];
-                        if (pfnCallback) /* Can be NULL see registration code */
-                            pfnCallback();
-                    } while (idxCallback-- > 0);
-                }
-                if (idxChunk == 0)
-                    break;
-                idxChunk--;
-                idxCallback = RT_ELEMENTS(g_apAtExit[0]->apfnCallbacks) - 1;
-            }
-        }
-
+        rtVccTermRunAtExit();
         rtVccInitializersRunTerm();
     }
@@ -175,28 +75,4 @@
 
 
-DECL_NO_INLINE(static, void) initProcExecPath(void)
-{
-    WCHAR wszPath[RTPATH_MAX];
-    UINT cwcPath = GetModuleFileNameW(NULL, wszPath, RT_ELEMENTS(wszPath));
-    if (cwcPath)
-    {
-        char *pszDst = g_szrtProcExePath;
-        int rc = RTUtf16ToUtf8Ex(wszPath, cwcPath, &pszDst, sizeof(g_szrtProcExePath), &g_cchrtProcExePath);
-        if (RT_SUCCESS(rc))
-        {
-            g_cchrtProcExeDir = g_offrtProcName = RTPathFilename(pszDst) - g_szrtProcExePath;
-            while (   g_cchrtProcExeDir >= 2
-                   && RTPATH_IS_SLASH(g_szrtProcExePath[g_cchrtProcExeDir - 1])
-                   && g_szrtProcExePath[g_cchrtProcExeDir - 2] != ':')
-                g_cchrtProcExeDir--;
-        }
-        else
-            RTMsgError("initProcExecPath: RTUtf16ToUtf8Ex failed: %Rrc\n", rc);
-    }
-    else
-        RTMsgError("initProcExecPath: GetModuleFileNameW failed: %Rhrc\n", GetLastError());
-}
-
-
 DECLASM(void) CustomMainEntrypoint(PPEB pPeb)
 {
@@ -204,6 +80,7 @@
      * Initialize stuff.
      */
+    rtVccInitSecurityCookie();
     InitStdHandles(pPeb->ProcessParameters);
-    initProcExecPath();
+    rtVccWinInitProcExecPath();
 
     RTEXITCODE rcExit;
