[Pkg-virtualbox-commits] [kbuild] 01/03: Imported Upstream version 0.1.9998svn2911+dfsg

Gianfranco Costamagna locutusofborg at moszumanska.debian.org
Tue Sep 13 14:40:40 UTC 2016


This is an automated email from the git hooks/post-receive script.

locutusofborg pushed a commit to branch experimental
in repository kbuild.

commit 96e32c91d68fe624656ef9bbe249a5d96f01c93d
Author: Gianfranco Costamagna <locutusofborg at debian.org>
Date:   Tue Sep 13 16:34:44 2016 +0200

    Imported Upstream version 0.1.9998svn2911+dfsg
---
 kBuild/tools/VCC100AMD64.kmk  |  14 +-
 kBuild/tools/VCC100X86.kmk    |  14 +-
 src/kWorker/kWorker.c         | 970 ++++++++++++++++++++++++++++++++++++++++--
 src/kmk/Makefile.kmk          |   6 +-
 src/kmk/kmkbuiltin.h          |   3 +-
 src/kmk/kmkbuiltin/cat.c      |  16 +-
 src/kmk/kmkbuiltin/err.c      | 112 ++++-
 src/kmk/kmkbuiltin/mscfakes.c |   6 +-
 src/kmk/kmkbuiltin/printf.c   | 126 +++++-
 src/kmk/kmkbuiltin/solfakes.c |   6 +-
 src/kmk/main.c                |   4 +-
 src/kmk/misc.c                |  89 ++++
 src/lib/Makefile.kmk          |   5 +-
 src/lib/maybe_con_fwrite.c    | 114 +++++
 src/lib/maybe_con_write.c     | 116 +++++
 src/lib/msc_buffered_printf.c | 254 +++++++++++
 src/lib/nt/ntstuff.h          |  55 ++-
 src/sed/Makefile.kmk          |   4 +-
 src/sed/lib/utils.c           |   5 +
 19 files changed, 1839 insertions(+), 80 deletions(-)

diff --git a/kBuild/tools/VCC100AMD64.kmk b/kBuild/tools/VCC100AMD64.kmk
index 5261eeb..a4740db 100644
--- a/kBuild/tools/VCC100AMD64.kmk
+++ b/kBuild/tools/VCC100AMD64.kmk
@@ -1,4 +1,4 @@
-# $Id: VCC100AMD64.kmk 2895 2016-09-08 13:28:37Z bird $
+# $Id: VCC100AMD64.kmk 2902 2016-09-09 17:15:22Z bird $
 ## @file
 # kBuild Tool Config - Visual C++ 10.0 (aka Visual 2010 and MSC v16), targeting AMD64.
 #
@@ -68,7 +68,8 @@ PATH_TOOL_VCC100AMD64_ATLMFC_LIB ?= $(PATH_TOOL_VCC100AMD64_ATLMFC)/lib/amd64
 TOOL_VCC100AMD64_CC  ?= $(EXEC_X86_WIN32) $(PATH_TOOL_VCC100AMD64_BIN)/cl.exe
 TOOL_VCC100AMD64_CXX ?= $(EXEC_X86_WIN32) $(PATH_TOOL_VCC100AMD64_BIN)/cl.exe
 TOOL_VCC100AMD64_AS  ?= $(EXEC_X86_WIN32) $(PATH_TOOL_VCC100AMD64_BIN)/ml64.exe
-TOOL_VCC100AMD64_AR  ?= $(EXEC_X86_WIN32) $(PATH_TOOL_VCC100AMD64_BIN)/lib.exe
+#TOOL_VCC100AMD64_AR  ?= $(EXEC_X86_WIN32) $(PATH_TOOL_VCC100AMD64_BIN)/lib.exe - just an exec wrapper for the below
+TOOL_VCC100AMD64_AR  ?= $(EXEC_X86_WIN32) $(PATH_TOOL_VCC100AMD64_BIN)/link.exe /LIB
 TOOL_VCC100AMD64_LD  ?= $(EXEC_X86_WIN32) $(PATH_TOOL_VCC100AMD64_BIN)/link.exe
 TOOL_VCC100AMD64_DUMPBIN ?= $(EXEC_X86_WIN32) $(PATH_TOOL_VCC100AMD64_BIN)/dumpbin.exe
 TOOL_VCC100AMD64_EDITBIN ?= $(EXEC_X86_WIN32) $(PATH_TOOL_VCC100AMD64_BIN)/editbin.exe
@@ -81,6 +82,7 @@ ifdef TOOL_VCC100AMD64_USE_KSUBMIT
   else
    TOOL_VCC100AMD64_KSUBMIT ?= kmk_builtin_kSubmit --32-bit
   endif
+  TOOL_VCC100AMD64_KSUBMIT_DD = $(TOOL_VCC100AMD64_KSUBMIT) --
  endif
 endif
 
@@ -301,7 +303,7 @@ define TOOL_VCC100AMD64_LINK_LIBRARY_CMDS
 			$(filter-out %.def,$(othersrc))) \
 			$(addprefix /DEF:,$(filter %.def,$(othersrc))) \
 			,\"$(arg)\")
-	$(QUIET)$(TOOL_VCC100AMD64_AR) $(flags) /OUT:$(out) @$(outbase).rsp
+	$(QUIET)$(TOOL_VCC100AMD64_KSUBMIT_DD) $(TOOL_VCC100AMD64_AR) $(flags) /OUT:$(out) @$(outbase).rsp
 endef
 
 
@@ -331,7 +333,7 @@ define TOOL_VCC100AMD64_LINK_PROGRAM_CMDS
 		    $(subst /,\\,$(objs)) \
 		    $(subst /,\\,$(libs)) \
 			,\"$(arg)\")
-	$(QUIET)$(TOOL_VCC100AMD64_LD) $(flags) \
+	$(QUIET)$(TOOL_VCC100AMD64_KSUBMIT_DD) $(TOOL_VCC100AMD64_LD) $(flags) \
 		/OUT:$(out) \
 		/MAPINFO:EXPORTS /INCREMENTAL:NO \
 		/MAP:$(outbase).map \
@@ -373,7 +375,7 @@ define TOOL_VCC100AMD64_LINK_DLL_CMDS
 		    $(subst /,\\,$(objs)) \
 		    $(subst /,\\,$(libs)) \
 			,\"$(arg)\")
-	$(QUIET)$(TOOL_VCC100AMD64_LD) $(flags) \
+	$(QUIET)$(TOOL_VCC100AMD64_KSUBMIT_DD) $(TOOL_VCC100AMD64_LD) $(flags) \
 		/OUT:$(out) \
 		/IMPLIB:$(outbase).lib \
 		/MAPINFO:EXPORTS /INCREMENTAL:NO \
@@ -419,7 +421,7 @@ define TOOL_VCC100AMD64_LINK_SYSMOD_CMDS
 		    $(subst /,\\,$(objs)) \
 		    $(subst /,\\,$(libs)) \
 			,\"$(arg)\")
-	$(QUIET)$(TOOL_VCC100AMD64_LD) $(flags) \
+	$(QUIET)$(TOOL_VCC100AMD64_KSUBMIT_DD) $(TOOL_VCC100AMD64_LD) $(flags) \
 		/OUT:$(out) \
 		/MAPINFO:EXPORTS /INCREMENTAL:NO \
 		/MAP:$(outbase).map \
diff --git a/kBuild/tools/VCC100X86.kmk b/kBuild/tools/VCC100X86.kmk
index e3ad436..95d6ac8 100644
--- a/kBuild/tools/VCC100X86.kmk
+++ b/kBuild/tools/VCC100X86.kmk
@@ -1,4 +1,4 @@
-# $Id: VCC100X86.kmk 2895 2016-09-08 13:28:37Z bird $
+# $Id: VCC100X86.kmk 2902 2016-09-09 17:15:22Z bird $
 ## @file
 # kBuild Tool Config - Visual C++ 10.0 (aka Visual 2010 and MSC v16), targeting x86.
 #
@@ -67,7 +67,8 @@ PATH_TOOL_VCC100X86_ATLMFC_LIB ?= $(PATH_TOOL_VCC100X86_ATLMFC)/lib
 TOOL_VCC100X86_CC  ?= $(EXEC_X86_WIN32) $(PATH_TOOL_VCC100X86_BIN)/cl.exe
 TOOL_VCC100X86_CXX ?= $(EXEC_X86_WIN32) $(PATH_TOOL_VCC100X86_BIN)/cl.exe
 TOOL_VCC100X86_AS  ?= $(EXEC_X86_WIN32) $(PATH_TOOL_VCC100X86_BIN)/ml.exe
-TOOL_VCC100X86_AR  ?= $(EXEC_X86_WIN32) $(PATH_TOOL_VCC100X86_BIN)/lib.exe
+#TOOL_VCC100X86_AR  ?= $(EXEC_X86_WIN32) $(PATH_TOOL_VCC100X86_BIN)/lib.exe - just an exec wrapper for the below
+TOOL_VCC100X86_AR  ?= $(EXEC_X86_WIN32) $(PATH_TOOL_VCC100X86_BIN)/link.exe /LIB
 TOOL_VCC100X86_LD  ?= $(EXEC_X86_WIN32) $(PATH_TOOL_VCC100X86_BIN)/link.exe
 TOOL_VCC100X86_DUMPBIN ?= $(EXEC_X86_WIN32) $(PATH_TOOL_VCC100X86_BIN)/dumpbin.exe
 TOOL_VCC100X86_EDITBIN ?= $(EXEC_X86_WIN32) $(PATH_TOOL_VCC100X86_BIN)/editbin.exe
@@ -76,6 +77,7 @@ TOOL_VCC100X86_MT  ?= $(EXEC_X86_WIN32) $(call TOOL_VCC100_FN_FIND_SDK_TOOL,mt.e
 ifdef TOOL_VCC100X86_USE_KSUBMIT
  ifeq ($(KBUILD_HOST),win)
   TOOL_VCC100X86_KSUBMIT ?= kmk_builtin_kSubmit --32-bit
+  TOOL_VCC100X86_KSUBMIT_DD = $(TOOL_VCC100X86_KSUBMIT) --
  endif
 endif
 
@@ -298,7 +300,7 @@ define TOOL_VCC100X86_LINK_LIBRARY_CMDS
 			$(filter-out %.def,$(othersrc))) \
 			$(addprefix /DEF:,$(filter %.def,$(othersrc))) \
 			,\"$(arg)\")
-	$(QUIET)$(TOOL_VCC100X86_AR) $(flags) /OUT:$(out) @$(outbase).rsp
+	$(QUIET)$(TOOL_VCC100X86_KSUBMIT_DD) $(TOOL_VCC100X86_AR) $(flags) /OUT:$(out) @$(outbase).rsp
 endef
 
 
@@ -328,7 +330,7 @@ define TOOL_VCC100X86_LINK_PROGRAM_CMDS
 		    $(subst /,\\,$(objs)) \
 		    $(subst /,\\,$(libs)) \
 			,\"$(arg)\")
-	$(QUIET)$(TOOL_VCC100X86_LD) $(flags) \
+	$(QUIET)$(TOOL_VCC100X86_KSUBMIT_DD) $(TOOL_VCC100X86_LD) $(flags) \
 		/OUT:$(out) \
 		/MAPINFO:EXPORTS /INCREMENTAL:NO \
 		/MAP:$(outbase).map \
@@ -370,7 +372,7 @@ define TOOL_VCC100X86_LINK_DLL_CMDS
 		    $(subst /,\\,$(objs)) \
 		    $(subst /,\\,$(libs)) \
 			,\"$(arg)\")
-	$(QUIET)$(TOOL_VCC100X86_LD) $(flags) \
+	$(QUIET)$(TOOL_VCC100X86_KSUBMIT_DD) $(TOOL_VCC100X86_LD) $(flags) \
 		/OUT:$(out) \
 		/IMPLIB:$(outbase).lib \
 		/MAPINFO:EXPORTS /INCREMENTAL:NO \
@@ -416,7 +418,7 @@ define TOOL_VCC100X86_LINK_SYSMOD_CMDS
 		    $(subst /,\\,$(objs)) \
 		    $(subst /,\\,$(libs)) \
 			,\"$(arg)\")
-	$(QUIET)$(TOOL_VCC100X86_LD) $(flags) \
+	$(QUIET)$(TOOL_VCC100X86_KSUBMIT_DD) $(TOOL_VCC100X86_LD) $(flags) \
 		/OUT:$(out) \
 		/MAPINFO:EXPORTS /INCREMENTAL:NO \
 		/MAP:$(outbase).map \
diff --git a/src/kWorker/kWorker.c b/src/kWorker/kWorker.c
index d4add04..6962738 100644
--- a/src/kWorker/kWorker.c
+++ b/src/kWorker/kWorker.c
@@ -1,4 +1,4 @@
-/* $Id: kWorker.c 2898 2016-09-08 15:38:50Z bird $ */
+/* $Id: kWorker.c 2906 2016-09-09 22:15:57Z bird $ */
 /** @file
  * kWorker - experimental process reuse worker for Windows.
  *
@@ -69,6 +69,11 @@ extern void nt_fullpath(const char *pszPath, char *pszFull, size_t cchFull);
  * they are included. */
 #define WITH_HASH_MD5_CACHE
 
+/** @def WITH_CONSOLE_OUTPUT_BUFFERING
+ * Enables buffering of all console output as well as removal of annoying
+ * source file echo by cl.exe. */
+#define WITH_CONSOLE_OUTPUT_BUFFERING
+
 
 /** String constant comma length.   */
 #define TUPLE(a_sz)                     a_sz, sizeof(a_sz) - 1
@@ -275,8 +280,8 @@ typedef struct KFSWCACHEDFILE
 /** Pointer to a cached filed. */
 typedef KFSWCACHEDFILE *PKFSWCACHEDFILE;
 
-
 #ifdef WITH_HASH_MD5_CACHE
+
 /** Pointer to a MD5 hash instance. */
 typedef struct KWHASHMD5 *PKWHASHMD5;
 /**
@@ -306,9 +311,9 @@ typedef struct KWHASHMD5
 } KWHASHMD5;
 /** Magic value for KWHASHMD5::uMagic (Les McCann). */
 # define KWHASHMD5_MAGIC    KUPTR_C(0x19350923)
-#endif /* WITH_HASH_MD5_CACHE */
-
 
+#endif /* WITH_HASH_MD5_CACHE */
+#ifdef WITH_TEMP_MEMORY_FILES
 
 typedef struct KWFSTEMPFILESEG *PKWFSTEMPFILESEG;
 typedef struct KWFSTEMPFILESEG
@@ -344,6 +349,52 @@ typedef struct KWFSTEMPFILE
     PKWFSTEMPFILESEG    paSegs;
 } KWFSTEMPFILE;
 
+#endif /* WITH_TEMP_MEMORY_FILES */
+#ifdef WITH_CONSOLE_OUTPUT_BUFFERING
+
+/**
+ * Console line buffer.
+ */
+typedef struct KWCONSOLEOUTPUTLINE
+{
+    /** The main output handle. */
+    HANDLE              hOutput;
+    /** Our backup handle. */
+    HANDLE              hBackup;
+    /** Set if this is a console handle. */
+    KBOOL               fIsConsole;
+    /** Amount of pending console output in wchar_t's. */
+    KU32                cwcBuf;
+    /** The allocated buffer size.   */
+    KU32                cwcBufAlloc;
+    /** Pending console output. */
+    wchar_t            *pwcBuf;
+} KWCONSOLEOUTPUTLINE;
+/** Pointer to a console line buffer. */
+typedef KWCONSOLEOUTPUTLINE *PKWCONSOLEOUTPUTLINE;
+
+/**
+ * Combined console buffer of complete lines.
+ */
+typedef struct KWCONSOLEOUTPUT
+{
+    /** The console output handle.
+     * INVALID_HANDLE_VALUE if we haven't got a console and shouldn't be doing any
+     * combined output buffering. */
+    HANDLE              hOutput;
+    /** The current code page for the console. */
+    KU32                uCodepage;
+    /** Amount of pending console output in wchar_t's. */
+    KU32                cwcBuf;
+    /** Number of times we've flushed it in any way (for cl.exe hack). */
+    KU32                cFlushes;
+    /** Pending console output. */
+    wchar_t             wszBuf[8192];
+} KWCONSOLEOUTPUT;
+/** Pointer to a combined console buffer. */
+typedef KWCONSOLEOUTPUT *PKWCONSOLEOUTPUT;
+
+#endif /* WITH_CONSOLE_OUTPUT_BUFFERING */
 
 /** Handle type.   */
 typedef enum KWHANDLETYPE
@@ -391,6 +442,18 @@ typedef struct KWVIRTALLOC
 } KWVIRTALLOC;
 
 
+/** Pointer to a heap (HeapCreate) tracker entry. */
+typedef struct KWHEAP *PKWHEAP;
+/**
+ * Tracking an heap (HeapCreate)
+ */
+typedef struct KWHEAP
+{
+    PKWHEAP             pNext;
+    HANDLE              hHeap;
+} KWHEAP;
+
+
 /** Pointer to a FlsAlloc/TlsAlloc tracker entry. */
 typedef struct KWLOCALSTORAGE *PKWLOCALSTORAGE;
 /**
@@ -403,6 +466,20 @@ typedef struct KWLOCALSTORAGE
 } KWLOCALSTORAGE;
 
 
+/** Pointer to an at exit callback record */
+typedef struct KWEXITCALLACK *PKWEXITCALLACK;
+/**
+ * At exit callback record.
+ */
+typedef struct KWEXITCALLACK
+{
+    PKWEXITCALLACK      pNext;
+    _onexit_t           pfnCallback;
+    /** At exit doesn't have an exit code. */
+    KBOOL               fAtExit;
+} KWEXITCALLACK;
+
+
 typedef enum KWTOOLTYPE
 {
     KWTOOLTYPE_INVALID = 0,
@@ -417,6 +494,7 @@ typedef enum KWTOOLHINT
     KWTOOLHINT_INVALID = 0,
     KWTOOLHINT_NONE,
     KWTOOLHINT_VISUAL_CPP_CL,
+    KWTOOLHINT_VISUAL_CPP_LINK,
     KWTOOLHINT_END
 } KWTOOLHINT;
 
@@ -525,11 +603,18 @@ typedef struct KWSANDBOX
 
     /** Head of the virtual alloc allocations. */
     PKWVIRTALLOC    pVirtualAllocHead;
+    /** Head of the heap list (HeapCreate).
+     * This is only done from images we forcibly restore.  */
+    PKWHEAP         pHeapHead;
     /** Head of the FlsAlloc indexes. */
     PKWLOCALSTORAGE pFlsAllocHead;
     /** Head of the TlsAlloc indexes. */
     PKWLOCALSTORAGE pTlsAllocHead;
 
+    /** The at exit callback head.
+     * This is only done from images we forcibly restore.  */
+    PKWEXITCALLACK  pExitCallbackHead;
+
     UNICODE_STRING  SavedCommandLine;
 
 #ifdef WITH_HASH_MD5_CACHE
@@ -553,6 +638,15 @@ typedef struct KWSANDBOX
         void           *pvRead;
     } LastHashRead;
 #endif
+
+#ifdef WITH_CONSOLE_OUTPUT_BUFFERING
+    /** Standard output (and whatever else) line buffer. */
+    KWCONSOLEOUTPUTLINE StdOut;
+    /** Standard error line buffer. */
+    KWCONSOLEOUTPUTLINE StdErr;
+    /** Combined buffer of completed lines. */
+    KWCONSOLEOUTPUT     Combined;
+#endif
 } KWSANDBOX;
 
 /** Replacement function entry. */
@@ -566,6 +660,9 @@ typedef struct KWREPLACEMENTFUNCTION
     const char *pszModule;
     /** The replacement function or data address. */
     KUPTR       pfnReplacement;
+    /** Only replace in the executable.
+     * @todo fix the reinitialization of non-native DLLs!  */
+    KBOOL       fOnlyExe;
 } KWREPLACEMENTFUNCTION;
 typedef KWREPLACEMENTFUNCTION const *PCKWREPLACEMENTFUNCTION;
 
@@ -639,6 +736,9 @@ static KU8          g_abDefLdBuf[16*1024*1024];
 static FNKLDRMODGETIMPORT kwLdrModuleGetImportCallback;
 static int kwLdrModuleResolveAndLookup(const char *pszName, PKWMODULE pExe, PKWMODULE pImporter, PKWMODULE *ppMod);
 static KBOOL kwSandboxHandleTableEnter(PKWSANDBOX pSandbox, PKWHANDLE pHandle);
+#ifdef WITH_CONSOLE_OUTPUT_BUFFERING
+static void kwSandboxConsoleWriteA(PKWSANDBOX pSandbox, PKWCONSOLEOUTPUTLINE pLineBuf, const char *pchBuffer, KU32 cchToWrite);
+#endif
 
 
 
@@ -1695,8 +1795,12 @@ static int kwLdrModuleGetImportCallback(PKLDRMOD pMod, KU32 iImport, KU32 iSymbo
                 if (   !g_aSandboxReplacements[i].pszModule
                     || kHlpStrICompAscii(g_aSandboxReplacements[i].pszModule, &pImpMod->pszPath[pImpMod->offFilename]) == 0)
                 {
-                    KW_LOG(("replacing %s!%s\n", &pImpMod->pszPath[pImpMod->offFilename], g_aSandboxReplacements[i].pszFunction));
-                    *puValue = g_aSandboxReplacements[i].pfnReplacement;
+                    if (   pCurMod->fExe
+                        || !g_aSandboxReplacements[i].fOnlyExe)
+                    {
+                        KW_LOG(("replacing %s!%s\n",&pImpMod->pszPath[pImpMod->offFilename], g_aSandboxReplacements[i].pszFunction));
+                        *puValue = g_aSandboxReplacements[i].pfnReplacement;
+                    }
                     break;
                 }
             }
@@ -2228,6 +2332,8 @@ static PKWTOOL kwToolEntryCreate(PKFSOBJ pToolFsObj)
             {
                 if (kHlpStrICompAscii(pToolFsObj->pszName, "cl.exe") == 0)
                     pTool->u.Sandboxed.enmHint = KWTOOLHINT_VISUAL_CPP_CL;
+                else if (kHlpStrICompAscii(pToolFsObj->pszName, "link.exe") == 0)
+                    pTool->u.Sandboxed.enmHint = KWTOOLHINT_VISUAL_CPP_LINK;
                 else
                     pTool->u.Sandboxed.enmHint = KWTOOLHINT_NONE;
                 kwToolAddModuleAndImports(pTool, pTool->u.Sandboxed.pExe);
@@ -2528,6 +2634,56 @@ static void __cdecl kwSandbox_msvcrt_terminate(void)
 }
 
 
+/** CRT - _onexit   */
+static _onexit_t __cdecl kwSandbox_msvcrt__onexit(_onexit_t pfnFunc)
+{
+    if (g_Sandbox.pTool->u.Sandboxed.enmHint == KWTOOLHINT_VISUAL_CPP_LINK)
+    {
+        PKWEXITCALLACK pCallback;
+        KW_LOG(("_onexit(%p)\n", pfnFunc));
+        kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
+
+        pCallback = kHlpAlloc(sizeof(*pCallback));
+        if (pCallback)
+        {
+            pCallback->pfnCallback = pfnFunc;
+            pCallback->fAtExit     = K_FALSE;
+            pCallback->pNext       = g_Sandbox.pExitCallbackHead;
+            g_Sandbox.pExitCallbackHead = pCallback;
+            return pfnFunc;
+        }
+        return NULL;
+    }
+    KW_LOG(("_onexit(%p) - IGNORED\n", pfnFunc));
+    return pfnFunc;
+}
+
+
+/** CRT - atexit   */
+static int __cdecl kwSandbox_msvcrt_atexit(int (__cdecl *pfnFunc)(void))
+{
+    if (g_Sandbox.pTool->u.Sandboxed.enmHint == KWTOOLHINT_VISUAL_CPP_LINK)
+    {
+        PKWEXITCALLACK pCallback;
+        kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
+        KW_LOG(("atexit(%p)\n", pfnFunc));
+
+        pCallback = kHlpAlloc(sizeof(*pCallback));
+        if (pCallback)
+        {
+            pCallback->pfnCallback = (_onexit_t)pfnFunc;
+            pCallback->fAtExit     = K_TRUE;
+            pCallback->pNext       = g_Sandbox.pExitCallbackHead;
+            g_Sandbox.pExitCallbackHead = pCallback;
+            return 0;
+        }
+        return -1;
+    }
+    KW_LOG(("atexit(%p) - IGNORED!\n", pfnFunc));
+    return 0;
+}
+
+
 /** Kernel32 - SetConsoleCtrlHandler(). */
 static BOOL WINAPI kwSandbox_Kernel32_SetConsoleCtrlHandler(PHANDLER_ROUTINE pfnHandler, BOOL fAdd)
 {
@@ -2540,6 +2696,7 @@ static BOOL WINAPI kwSandbox_Kernel32_SetConsoleCtrlHandler(PHANDLER_ROUTINE pfn
 static int __cdecl kwSandbox_msvcrt___getmainargs(int *pargc, char ***pargv, char ***penvp,
                                                   int dowildcard, int const *piNewMode)
 {
+    kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
     *pargc = g_Sandbox.cArgs;
     *pargv = g_Sandbox.papszArgs;
     *penvp = g_Sandbox.environ;
@@ -2553,6 +2710,7 @@ static int __cdecl kwSandbox_msvcrt___getmainargs(int *pargc, char ***pargv, cha
 static int __cdecl kwSandbox_msvcrt___wgetmainargs(int *pargc, wchar_t ***pargv, wchar_t ***penvp,
                                                    int dowildcard, int const *piNewMode)
 {
+    kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
     *pargc = g_Sandbox.cArgs;
     *pargv = g_Sandbox.papwszArgs;
     *penvp = g_Sandbox.wenviron;
@@ -2566,6 +2724,7 @@ static int __cdecl kwSandbox_msvcrt___wgetmainargs(int *pargc, wchar_t ***pargv,
 /** Kernel32 - GetCommandLineA()  */
 static LPCSTR /*LPSTR*/ WINAPI kwSandbox_Kernel32_GetCommandLineA(VOID)
 {
+    kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
     return g_Sandbox.pszCmdLine;
 }
 
@@ -2573,6 +2732,7 @@ static LPCSTR /*LPSTR*/ WINAPI kwSandbox_Kernel32_GetCommandLineA(VOID)
 /** Kernel32 - GetCommandLineW()  */
 static LPCWSTR /*LPWSTR*/ WINAPI kwSandbox_Kernel32_GetCommandLineW(VOID)
 {
+    kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
     return g_Sandbox.pwszCmdLine;
 }
 
@@ -2604,6 +2764,7 @@ static VOID WINAPI kwSandbox_Kernel32_GetStartupInfoW(LPSTARTUPINFOW pStartupInf
 /** CRT - __p___argc().  */
 static int * __cdecl kwSandbox_msvcrt___p___argc(void)
 {
+    kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
     return &g_Sandbox.cArgs;
 }
 
@@ -2611,6 +2772,7 @@ static int * __cdecl kwSandbox_msvcrt___p___argc(void)
 /** CRT - __p___argv().  */
 static char *** __cdecl kwSandbox_msvcrt___p___argv(void)
 {
+    kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
     return &g_Sandbox.papszArgs;
 }
 
@@ -2618,6 +2780,7 @@ static char *** __cdecl kwSandbox_msvcrt___p___argv(void)
 /** CRT - __p___sargv().  */
 static wchar_t *** __cdecl kwSandbox_msvcrt___p___wargv(void)
 {
+    kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
     return &g_Sandbox.papwszArgs;
 }
 
@@ -2625,6 +2788,7 @@ static wchar_t *** __cdecl kwSandbox_msvcrt___p___wargv(void)
 /** CRT - __p__acmdln().  */
 static char ** __cdecl kwSandbox_msvcrt___p__acmdln(void)
 {
+    kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
     return (char **)&g_Sandbox.pszCmdLine;
 }
 
@@ -2632,6 +2796,7 @@ static char ** __cdecl kwSandbox_msvcrt___p__acmdln(void)
 /** CRT - __p__acmdln().  */
 static wchar_t ** __cdecl kwSandbox_msvcrt___p__wcmdln(void)
 {
+    kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
     return &g_Sandbox.pwszCmdLine;
 }
 
@@ -2639,6 +2804,7 @@ static wchar_t ** __cdecl kwSandbox_msvcrt___p__wcmdln(void)
 /** CRT - __p__pgmptr().  */
 static char ** __cdecl kwSandbox_msvcrt___p__pgmptr(void)
 {
+    kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
     return &g_Sandbox.pgmptr;
 }
 
@@ -2646,6 +2812,7 @@ static char ** __cdecl kwSandbox_msvcrt___p__pgmptr(void)
 /** CRT - __p__wpgmptr().  */
 static wchar_t ** __cdecl kwSandbox_msvcrt___p__wpgmptr(void)
 {
+    kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
     return &g_Sandbox.wpgmptr;
 }
 
@@ -2653,6 +2820,7 @@ static wchar_t ** __cdecl kwSandbox_msvcrt___p__wpgmptr(void)
 /** CRT - _get_pgmptr().  */
 static errno_t __cdecl kwSandbox_msvcrt__get_pgmptr(char **ppszValue)
 {
+    kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
     *ppszValue = g_Sandbox.pgmptr;
     return 0;
 }
@@ -2661,6 +2829,7 @@ static errno_t __cdecl kwSandbox_msvcrt__get_pgmptr(char **ppszValue)
 /** CRT - _get_wpgmptr().  */
 static errno_t __cdecl kwSandbox_msvcrt__get_wpgmptr(wchar_t **ppwszValue)
 {
+    kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
     *ppwszValue = g_Sandbox.wpgmptr;
     return 0;
 }
@@ -2668,6 +2837,7 @@ static errno_t __cdecl kwSandbox_msvcrt__get_wpgmptr(wchar_t **ppwszValue)
 /** Just in case. */
 static void kwSandbox_msvcrt__wincmdln(void)
 {
+    kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
     KWFS_TODO();
 }
 
@@ -2675,6 +2845,7 @@ static void kwSandbox_msvcrt__wincmdln(void)
 /** Just in case. */
 static void kwSandbox_msvcrt__wwincmdln(void)
 {
+    kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
     KWFS_TODO();
 }
 
@@ -2683,14 +2854,26 @@ static HANDLE WINAPI kwSandbox_Kernel32_CreateThread(LPSECURITY_ATTRIBUTES pSecA
                                                      PTHREAD_START_ROUTINE pfnThreadProc, PVOID pvUser,
                                                      DWORD fFlags, PDWORD pidThread)
 {
-    KWFS_TODO();
-    return NULL;
+    HANDLE hThread = NULL;
+    KW_LOG(("CreateThread: pSecAttr=%p (inh=%d) cbStack=%#x pfnThreadProc=%p pvUser=%p fFlags=%#x pidThread=%p\n",
+            pSecAttr, pSecAttr ? pSecAttr->bInheritHandle : 0, cbStack, pfnThreadProc, pvUser, fFlags, pidThread));
+    kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
+    if (g_Sandbox.pTool->u.Sandboxed.enmHint == KWTOOLHINT_VISUAL_CPP_LINK)
+    {
+        /* Allow link::DbgThread. */
+        hThread = CreateThread(pSecAttr, cbStack, pfnThreadProc, pvUser, fFlags, pidThread);
+        KW_LOG(("CreateThread -> %p, *pidThread=%#x\n", hThread, pidThread ? *pidThread : 0));
+    }
+    else
+        KWFS_TODO();
+    return hThread;
 }
 
 
 /** _beginthread - create a new thread. */
 static uintptr_t __cdecl kwSandbox_msvcrt__beginthread(void (__cdecl *pfnThreadProc)(void *), unsigned cbStack, void *pvUser)
 {
+    kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
     KWFS_TODO();
     return 0;
 }
@@ -2701,6 +2884,7 @@ static uintptr_t __cdecl kwSandbox_msvcrt__beginthreadex(void *pvSecAttr, unsign
                                                          unsigned (__stdcall *pfnThreadProc)(void *), void *pvUser,
                                                          unsigned fCreate, unsigned *pidThread)
 {
+    kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
     KWFS_TODO();
     return 0;
 }
@@ -2718,11 +2902,13 @@ static uintptr_t __cdecl kwSandbox_msvcrt__beginthreadex(void *pvSecAttr, unsign
 static LPCH WINAPI kwSandbox_Kernel32_GetEnvironmentStringsA(void)
 {
     char *pszzEnv;
-
-    /* Figure how space much we need first.  */
     char *pszCur;
     KSIZE cbNeeded = 1;
     KSIZE iVar = 0;
+
+    kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
+
+    /* Figure how space much we need first.  */
     while ((pszCur = g_Sandbox.papszEnvVars[iVar++]) != NULL)
         cbNeeded += kHlpStrLen(pszCur) + 1;
 
@@ -2773,11 +2959,13 @@ static LPCH WINAPI kwSandbox_Kernel32_GetEnvironmentStrings(void)
 static LPWCH WINAPI kwSandbox_Kernel32_GetEnvironmentStringsW(void)
 {
     wchar_t *pwszzEnv;
-
-    /* Figure how space much we need first.  */
     wchar_t *pwszCur;
     KSIZE    cwcNeeded = 1;
     KSIZE    iVar = 0;
+
+    kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
+
+    /* Figure how space much we need first.  */
     while ((pwszCur = g_Sandbox.papwszEnvVars[iVar++]) != NULL)
         cwcNeeded += kwUtf16Len(pwszCur) + 1;
 
@@ -2806,6 +2994,7 @@ static LPWCH WINAPI kwSandbox_Kernel32_GetEnvironmentStringsW(void)
 static BOOL WINAPI kwSandbox_Kernel32_FreeEnvironmentStringsA(LPCH pszzEnv)
 {
     KW_LOG(("FreeEnvironmentStringsA: %p -> TRUE\n", pszzEnv));
+    kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
     kHlpFree(pszzEnv);
     return TRUE;
 }
@@ -2815,6 +3004,7 @@ static BOOL WINAPI kwSandbox_Kernel32_FreeEnvironmentStringsA(LPCH pszzEnv)
 static BOOL WINAPI kwSandbox_Kernel32_FreeEnvironmentStringsW(LPWCH pwszzEnv)
 {
     KW_LOG(("FreeEnvironmentStringsW: %p -> TRUE\n", pwszzEnv));
+    kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
     kHlpFree(pwszzEnv);
     return TRUE;
 }
@@ -3142,7 +3332,10 @@ static wchar_t *kwSandboxDoGetEnvW(PKWSANDBOX pSandbox, const wchar_t *pwcVar, K
 /** Kernel32 - GetEnvironmentVariableA()  */
 static DWORD WINAPI kwSandbox_Kernel32_GetEnvironmentVariableA(LPCSTR pszVar, LPSTR pszValue, DWORD cbValue)
 {
-    char *pszFoundValue = kwSandboxDoGetEnvA(&g_Sandbox, pszVar, kHlpStrLen(pszVar));
+    char *pszFoundValue;
+    kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
+
+    pszFoundValue = kwSandboxDoGetEnvA(&g_Sandbox, pszVar, kHlpStrLen(pszVar));
     if (pszFoundValue)
     {
         DWORD cchRet = kwStrCopyStyle1(pszFoundValue, pszValue, cbValue);
@@ -3158,7 +3351,10 @@ static DWORD WINAPI kwSandbox_Kernel32_GetEnvironmentVariableA(LPCSTR pszVar, LP
 /** Kernel32 - GetEnvironmentVariableW()  */
 static DWORD WINAPI kwSandbox_Kernel32_GetEnvironmentVariableW(LPCWSTR pwszVar, LPWSTR pwszValue, DWORD cwcValue)
 {
-    wchar_t *pwszFoundValue = kwSandboxDoGetEnvW(&g_Sandbox, pwszVar, kwUtf16Len(pwszVar));
+    wchar_t *pwszFoundValue;
+    kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
+
+    pwszFoundValue = kwSandboxDoGetEnvW(&g_Sandbox, pwszVar, kwUtf16Len(pwszVar));
     if (pwszFoundValue)
     {
         DWORD cchRet = kwUtf16CopyStyle1(pwszFoundValue, pwszValue, cwcValue);
@@ -3175,6 +3371,8 @@ static DWORD WINAPI kwSandbox_Kernel32_GetEnvironmentVariableW(LPCWSTR pwszVar,
 static BOOL WINAPI kwSandbox_Kernel32_SetEnvironmentVariableA(LPCSTR pszVar, LPCSTR pszValue)
 {
     int rc;
+    kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
+
     if (pszValue)
         rc = kwSandboxDoSetEnvA(&g_Sandbox, pszVar, kHlpStrLen(pszVar), pszValue);
     else
@@ -3197,6 +3395,8 @@ static BOOL WINAPI kwSandbox_Kernel32_SetEnvironmentVariableA(LPCSTR pszVar, LPC
 static BOOL WINAPI kwSandbox_Kernel32_SetEnvironmentVariableW(LPCWSTR pwszVar, LPCWSTR pwszValue)
 {
     int rc;
+    kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
+
     if (pwszValue)
         rc = kwSandboxDoSetEnvW(&g_Sandbox, pwszVar, kwUtf16Len(pwszVar), pwszValue);
     else
@@ -3218,6 +3418,7 @@ static BOOL WINAPI kwSandbox_Kernel32_SetEnvironmentVariableW(LPCWSTR pwszVar, L
 /** Kernel32 - ExpandEnvironmentStringsA()  */
 static DWORD WINAPI kwSandbox_Kernel32_ExpandEnvironmentStringsA(LPCSTR pszSrc, LPSTR pwszDst, DWORD cbDst)
 {
+    kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
     KWFS_TODO();
     return 0;
 }
@@ -3226,6 +3427,7 @@ static DWORD WINAPI kwSandbox_Kernel32_ExpandEnvironmentStringsA(LPCSTR pszSrc,
 /** Kernel32 - ExpandEnvironmentStringsW()  */
 static DWORD WINAPI kwSandbox_Kernel32_ExpandEnvironmentStringsW(LPCWSTR pwszSrc, LPWSTR pwszDst, DWORD cbDst)
 {
+    kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
     KWFS_TODO();
     return 0;
 }
@@ -3235,7 +3437,10 @@ static DWORD WINAPI kwSandbox_Kernel32_ExpandEnvironmentStringsW(LPCWSTR pwszSrc
 static int __cdecl kwSandbox_msvcrt__putenv(const char *pszVarEqualValue)
 {
     int rc;
-    char const *pszEqual = kHlpStrChr(pszVarEqualValue, '=');
+    char const *pszEqual;
+    kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
+
+    pszEqual = kHlpStrChr(pszVarEqualValue, '=');
     if (pszEqual)
     {
         rc = kwSandboxDoSetEnvA(&g_Sandbox, pszVarEqualValue, pszEqual - pszVarEqualValue, pszEqual + 1);
@@ -3258,7 +3463,10 @@ static int __cdecl kwSandbox_msvcrt__putenv(const char *pszVarEqualValue)
 static int __cdecl kwSandbox_msvcrt__wputenv(const wchar_t *pwszVarEqualValue)
 {
     int rc;
-    wchar_t const *pwszEqual = wcschr(pwszVarEqualValue, '=');
+    wchar_t const *pwszEqual;
+    kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
+
+    pwszEqual = wcschr(pwszVarEqualValue, '=');
     if (pwszEqual)
     {
         rc = kwSandboxDoSetEnvW(&g_Sandbox, pwszVarEqualValue, pwszEqual - pwszVarEqualValue, pwszEqual + 1);
@@ -3280,7 +3488,10 @@ static int __cdecl kwSandbox_msvcrt__wputenv(const wchar_t *pwszVarEqualValue)
 /** CRT - _putenv_s(). */
 static errno_t __cdecl kwSandbox_msvcrt__putenv_s(const char *pszVar, const char *pszValue)
 {
-    char const *pszEqual = kHlpStrChr(pszVar, '=');
+    char const *pszEqual;
+    kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
+
+    pszEqual = kHlpStrChr(pszVar, '=');
     if (pszEqual == NULL)
     {
         if (pszValue)
@@ -3309,7 +3520,10 @@ static errno_t __cdecl kwSandbox_msvcrt__putenv_s(const char *pszVar, const char
 /** CRT - _wputenv_s(). */
 static errno_t __cdecl kwSandbox_msvcrt__wputenv_s(const wchar_t *pwszVar, const wchar_t *pwszValue)
 {
-    wchar_t const *pwszEqual = wcschr(pwszVar, '=');
+    wchar_t const *pwszEqual;
+    kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
+
+    pwszEqual = wcschr(pwszVar, '=');
     if (pwszEqual == NULL)
     {
         if (pwszValue)
@@ -3339,6 +3553,7 @@ static errno_t __cdecl kwSandbox_msvcrt__wputenv_s(const wchar_t *pwszVar, const
 static char *** __cdecl kwSandbox_msvcrt___p___initenv(void)
 {
     KW_LOG(("__p___initenv\n"));
+    kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
     KWFS_TODO();
     return &g_Sandbox.initenv;
 }
@@ -3348,6 +3563,7 @@ static char *** __cdecl kwSandbox_msvcrt___p___initenv(void)
 static wchar_t *** __cdecl kwSandbox_msvcrt___p___winitenv(void)
 {
     KW_LOG(("__p___winitenv\n"));
+    kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
     KWFS_TODO();
     return &g_Sandbox.winitenv;
 }
@@ -3357,6 +3573,7 @@ static wchar_t *** __cdecl kwSandbox_msvcrt___p___winitenv(void)
 static char *** __cdecl kwSandbox_msvcrt___p__environ(void)
 {
     KW_LOG(("__p__environ\n"));
+    kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
     return &g_Sandbox.environ;
 }
 
@@ -3365,6 +3582,7 @@ static char *** __cdecl kwSandbox_msvcrt___p__environ(void)
 static wchar_t *** __cdecl kwSandbox_msvcrt___p__wenviron(void)
 {
     KW_LOG(("__p__wenviron\n"));
+    kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
     return &g_Sandbox.wenviron;
 }
 
@@ -3374,6 +3592,7 @@ static wchar_t *** __cdecl kwSandbox_msvcrt___p__wenviron(void)
 static KUPTR /*void*/ __cdecl kwSandbox_msvcrt__get_environ(char ***ppapszEnviron)
 {
     KWFS_TODO(); /** @todo check the callers expectations! */
+    kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
     *ppapszEnviron = g_Sandbox.environ;
     return 0;
 }
@@ -3384,6 +3603,7 @@ static KUPTR /*void*/ __cdecl kwSandbox_msvcrt__get_environ(char ***ppapszEnviro
 static KUPTR /*void*/ __cdecl kwSandbox_msvcrt__get_wenviron(wchar_t ***ppapwszEnviron)
 {
     KWFS_TODO(); /** @todo check the callers expectations! */
+    kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
     *ppapwszEnviron = g_Sandbox.wenviron;
     return 0;
 }
@@ -3521,6 +3741,7 @@ static HMODULE WINAPI kwSandbox_Kernel32_LoadLibraryExA(LPCSTR pszFilename, HAND
     PKWDYNLOAD  pDynLoad;
     PKWMODULE   pMod;
     int         rc;
+    kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
 
     /*
      * Deal with a couple of extremely unlikely special cases right away.
@@ -3668,6 +3889,7 @@ static HMODULE WINAPI kwSandbox_Kernel32_LoadLibraryW(LPCWSTR pwszFilename)
 static BOOL WINAPI kwSandbox_Kernel32_FreeLibrary(HMODULE hmod)
 {
     /* Ignored, we like to keep everything loaded. */
+    kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
     return TRUE;
 }
 
@@ -3677,6 +3899,7 @@ static HMODULE WINAPI kwSandbox_Kernel32_GetModuleHandleA(LPCSTR pszModule)
 {
     KSIZE i;
     KSIZE cchModule;
+    kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
 
     /*
      * The executable.
@@ -3707,6 +3930,7 @@ static HMODULE WINAPI kwSandbox_Kernel32_GetModuleHandleW(LPCWSTR pwszModule)
 {
     KSIZE i;
     KSIZE cwcModule;
+    kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
 
     /*
      * The executable.
@@ -3735,7 +3959,11 @@ static HMODULE WINAPI kwSandbox_Kernel32_GetModuleHandleW(LPCWSTR pwszModule)
 /** Used to debug dynamically resolved procedures. */
 static UINT WINAPI kwSandbox_BreakIntoDebugger(void *pv1, void *pv2, void *pv3, void *pv4)
 {
+#ifdef _MSC_VER
+    __debugbreak();
+#else
     KWFS_TODO();
+#endif
     return -1;
 }
 
@@ -3744,11 +3972,13 @@ static UINT WINAPI kwSandbox_BreakIntoDebugger(void *pv1, void *pv2, void *pv3,
 static FARPROC WINAPI kwSandbox_Kernel32_GetProcAddress(HMODULE hmod, LPCSTR pszProc)
 {
     KSIZE i;
+    PKWMODULE pMod;
+    kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
 
     /*
      * Try locate the module.
      */
-    PKWMODULE pMod = kwToolLocateModuleByHandle(g_Sandbox.pTool, hmod);
+    pMod = kwToolLocateModuleByHandle(g_Sandbox.pTool, hmod);
     if (pMod)
     {
         KLDRADDR uValue;
@@ -3794,7 +4024,10 @@ static FARPROC WINAPI kwSandbox_Kernel32_GetProcAddress(HMODULE hmod, LPCSTR psz
 /** Kernel32 - GetModuleFileNameA()   */
 static DWORD WINAPI kwSandbox_Kernel32_GetModuleFileNameA(HMODULE hmod, LPSTR pszFilename, DWORD cbFilename)
 {
-    PKWMODULE pMod = kwToolLocateModuleByHandle(g_Sandbox.pTool, hmod);
+    PKWMODULE pMod;
+    kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
+
+    pMod = kwToolLocateModuleByHandle(g_Sandbox.pTool, hmod);
     if (pMod != NULL)
     {
         DWORD cbRet = kwStrCopyStyle1(pMod->pszPath, pszFilename, cbFilename);
@@ -3809,7 +4042,10 @@ static DWORD WINAPI kwSandbox_Kernel32_GetModuleFileNameA(HMODULE hmod, LPSTR ps
 /** Kernel32 - GetModuleFileNameW()   */
 static DWORD WINAPI kwSandbox_Kernel32_GetModuleFileNameW(HMODULE hmod, LPWSTR pwszFilename, DWORD cbFilename)
 {
-    PKWMODULE pMod = kwToolLocateModuleByHandle(g_Sandbox.pTool, hmod);
+    PKWMODULE pMod;
+    kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
+
+    pMod = kwToolLocateModuleByHandle(g_Sandbox.pTool, hmod);
     if (pMod)
     {
         DWORD cwcRet = kwUtf16CopyStyle1(pMod->pwszPath, pwszFilename, cbFilename);
@@ -4302,6 +4538,7 @@ static PKFSWCACHEDFILE kwFsObjCacheNewFile(PKFSOBJ pFsObj)
     MY_OBJECT_ATTRIBUTES    ObjAttr;
     MY_UNICODE_STRING       UniStr;
     MY_NTSTATUS             rcNt;
+    kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
 
     /*
      * Open the file relative to the parent directory.
@@ -4474,7 +4711,10 @@ static HANDLE WINAPI kwSandbox_Kernel32_CreateFileA(LPCSTR pszFilename, DWORD dw
                     if (kwFsIsCachableExtensionA(pszExt, K_FALSE /*fAttrQuery*/))
                     {
                         KFSLOOKUPERROR enmError;
-                        PKFSOBJ pFsObj = kFsCacheLookupNoMissingA(g_pFsCache, pszFilename, &enmError);
+                        PKFSOBJ pFsObj;
+                        kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
+
+                        pFsObj = kFsCacheLookupNoMissingA(g_pFsCache, pszFilename, &enmError);
                         if (pFsObj)
                         {
                             KBOOL fRc = kwFsObjCacheCreateFile(pFsObj, dwDesiredAccess, pSecAttrs && pSecAttrs->bInheritHandle,
@@ -4553,7 +4793,7 @@ static HANDLE WINAPI kwSandbox_Kernel32_CreateFileW(LPCWSTR pwszFilename, DWORD
                 {
                     if (kwFsIsCachablePathExtensionW(pwszFilename, K_FALSE /*fAttrQuery*/))
                     {
-                        /** @todo rewrite to pure UTF-16. */
+                        /** @todo rewrite in pure UTF-16. */
                         char szTmp[2048];
                         KSIZE cch = kwUtf16ToStr(pwszFilename, szTmp, sizeof(szTmp));
                         if (cch < sizeof(szTmp))
@@ -4584,6 +4824,7 @@ static HANDLE WINAPI kwSandbox_Kernel32_CreateFileW(LPCWSTR pwszFilename, DWORD
 static DWORD WINAPI kwSandbox_Kernel32_SetFilePointer(HANDLE hFile, LONG cbMove, PLONG pcbMoveHi, DWORD dwMoveMethod)
 {
     KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hFile);
+    kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
     if (idxHandle < g_Sandbox.cHandles)
     {
         PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle];
@@ -4664,6 +4905,7 @@ static BOOL WINAPI kwSandbox_Kernel32_SetFilePointerEx(HANDLE hFile, LARGE_INTEG
                                                        DWORD dwMoveMethod)
 {
     KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hFile);
+    kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
     if (idxHandle < g_Sandbox.cHandles)
     {
         PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle];
@@ -4743,6 +4985,7 @@ static BOOL WINAPI kwSandbox_Kernel32_ReadFile(HANDLE hFile, LPVOID pvBuffer, DW
                                                LPOVERLAPPED pOverlapped)
 {
     KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hFile);
+    kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
     if (idxHandle < g_Sandbox.cHandles)
     {
         PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle];
@@ -4858,6 +5101,7 @@ static BOOL WINAPI kwSandbox_Kernel32_ReadFileEx(HANDLE hFile, LPVOID pvBuffer,
                                                  LPOVERLAPPED_COMPLETION_ROUTINE pfnCompletionRoutine)
 {
     KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hFile);
+    kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
     if (idxHandle < g_Sandbox.cHandles)
     {
         PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle];
@@ -4934,6 +5178,7 @@ static BOOL WINAPI kwSandbox_Kernel32_WriteFile(HANDLE hFile, LPCVOID pvBuffer,
                                                 LPOVERLAPPED pOverlapped)
 {
     KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hFile);
+    kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
     if (idxHandle < g_Sandbox.cHandles)
     {
         PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle];
@@ -5012,6 +5257,23 @@ static BOOL WINAPI kwSandbox_Kernel32_WriteFile(HANDLE hFile, LPCVOID pvBuffer,
         }
     }
 
+#ifdef WITH_CONSOLE_OUTPUT_BUFFERING
+    /*
+     * Check for stdout and stderr.
+     */
+    if (   g_Sandbox.StdErr.hOutput == hFile
+        || g_Sandbox.StdOut.hOutput == hFile)
+    {
+        PKWCONSOLEOUTPUTLINE pLineBuf = g_Sandbox.StdErr.hOutput == hFile ? &g_Sandbox.StdErr : &g_Sandbox.StdOut;
+        if (pLineBuf->fIsConsole)
+        {
+            kwSandboxConsoleWriteA(&g_Sandbox, pLineBuf, (const char *)pvBuffer, cbToWrite);
+            KWFS_LOG(("WriteFile(console) -> TRUE\n", hFile));
+            return TRUE;
+        }
+    }
+#endif
+
     KWFS_LOG(("WriteFile(%p)\n", hFile));
     return WriteFile(hFile, pvBuffer, cbToWrite, pcbActuallyWritten, pOverlapped);
 }
@@ -5022,6 +5284,7 @@ static BOOL WINAPI kwSandbox_Kernel32_WriteFileEx(HANDLE hFile, LPCVOID pvBuffer
                                                   LPOVERLAPPED_COMPLETION_ROUTINE pfnCompletionRoutine)
 {
     KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hFile);
+    kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
     if (idxHandle < g_Sandbox.cHandles)
     {
         PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle];
@@ -5040,6 +5303,7 @@ static BOOL WINAPI kwSandbox_Kernel32_WriteFileEx(HANDLE hFile, LPCVOID pvBuffer
 static BOOL WINAPI kwSandbox_Kernel32_SetEndOfFile(HANDLE hFile)
 {
     KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hFile);
+    kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
     if (idxHandle < g_Sandbox.cHandles)
     {
         PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle];
@@ -5086,6 +5350,7 @@ static BOOL WINAPI kwSandbox_Kernel32_SetEndOfFile(HANDLE hFile)
 static BOOL WINAPI kwSandbox_Kernel32_GetFileType(HANDLE hFile)
 {
     KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hFile);
+    kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
     if (idxHandle < g_Sandbox.cHandles)
     {
         PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle];
@@ -5113,6 +5378,7 @@ static BOOL WINAPI kwSandbox_Kernel32_GetFileType(HANDLE hFile)
 static DWORD WINAPI kwSandbox_Kernel32_GetFileSize(HANDLE hFile, LPDWORD pcbHighDword)
 {
     KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hFile);
+    kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
     if (idxHandle < g_Sandbox.cHandles)
     {
         PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle];
@@ -5148,6 +5414,7 @@ static DWORD WINAPI kwSandbox_Kernel32_GetFileSize(HANDLE hFile, LPDWORD pcbHigh
 static BOOL WINAPI kwSandbox_Kernel32_GetFileSizeEx(HANDLE hFile, PLARGE_INTEGER pcbFile)
 {
     KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hFile);
+    kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
     if (idxHandle < g_Sandbox.cHandles)
     {
         PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle];
@@ -5184,6 +5451,7 @@ static HANDLE WINAPI kwSandbox_Kernel32_CreateFileMappingW(HANDLE hFile, LPSECUR
                                                            DWORD dwMaximumSizeLow, LPCWSTR pwszName)
 {
     KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hFile);
+    kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
     if (idxHandle < g_Sandbox.cHandles)
     {
         PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle];
@@ -5223,6 +5491,7 @@ static HANDLE WINAPI kwSandbox_Kernel32_MapViewOfFile(HANDLE hSection, DWORD dwD
                                                       DWORD offFileHigh, DWORD offFileLow, SIZE_T cbToMap)
 {
     KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hSection);
+    kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
     if (idxHandle < g_Sandbox.cHandles)
     {
         PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle];
@@ -5308,6 +5577,7 @@ static BOOL WINAPI kwSandbox_Kernel32_UnmapViewOfFile(LPCVOID pvBase)
 {
     /* Is this one of our temporary mappings? */
     PKWFSTEMPFILE pCur = g_Sandbox.pTempFileHead;
+    kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
     while (pCur)
     {
         if (   pCur->cMappings > 0
@@ -5334,6 +5604,7 @@ static BOOL WINAPI kwSandbox_Kernel32_CloseHandle(HANDLE hObject)
 {
     BOOL        fRet;
     KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hObject);
+    kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
     if (   idxHandle < g_Sandbox.cHandles
         && g_Sandbox.papHandles[idxHandle] != NULL)
     {
@@ -5373,7 +5644,10 @@ static DWORD WINAPI kwSandbox_Kernel32_GetFileAttributesA(LPCSTR pszFilename)
     if (kwFsIsCachableExtensionA(pszExt, K_TRUE /*fAttrQuery*/))
     {
         KFSLOOKUPERROR enmError;
-        PKFSOBJ pFsObj = kFsCacheLookupNoMissingA(g_pFsCache, pszFilename, &enmError);
+        PKFSOBJ pFsObj;
+        kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
+
+        pFsObj = kFsCacheLookupNoMissingA(g_pFsCache, pszFilename, &enmError);
         if (pFsObj)
         {
             kHlpAssert(pFsObj->fHaveStats);
@@ -5403,7 +5677,10 @@ static DWORD WINAPI kwSandbox_Kernel32_GetFileAttributesW(LPCWSTR pwszFilename)
     if (kwFsIsCachablePathExtensionW(pwszFilename, K_TRUE /*fAttrQuery*/))
     {
         KFSLOOKUPERROR enmError;
-        PKFSOBJ pFsObj = kFsCacheLookupNoMissingW(g_pFsCache, pwszFilename, &enmError);
+        PKFSOBJ pFsObj;
+        kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
+
+        pFsObj = kFsCacheLookupNoMissingW(g_pFsCache, pwszFilename, &enmError);
         if (pFsObj)
         {
             kHlpAssert(pFsObj->fHaveStats);
@@ -5435,7 +5712,10 @@ static DWORD WINAPI kwSandbox_Kernel32_GetShortPathNameW(LPCWSTR pwszLongPath, L
     if (kwFsIsCachablePathExtensionW(pwszLongPath, K_TRUE /*fAttrQuery*/))
     {
         KFSLOOKUPERROR enmError;
-        PKFSOBJ pObj = kFsCacheLookupW(g_pFsCache, pwszLongPath, &enmError);
+        PKFSOBJ pObj;
+        kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
+
+        pObj = kFsCacheLookupW(g_pFsCache, pwszLongPath, &enmError);
         if (pObj)
         {
             if (pObj->bObjType != KFSOBJ_TYPE_MISSING)
@@ -5487,6 +5767,7 @@ static BOOL WINAPI kwSandbox_Kernel32_DeleteFileW(LPCWSTR pwszFilename)
     if (   g_Sandbox.pTool->u.Sandboxed.enmHint == KWTOOLHINT_VISUAL_CPP_CL
         && kwFsIsClTempFileW(pwszFilename))
     {
+        kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
         KWFS_LOG(("DeleteFileW(%s) -> TRUE [temp]\n", pwszFilename));
         fRc = TRUE;
     }
@@ -5501,6 +5782,463 @@ static BOOL WINAPI kwSandbox_Kernel32_DeleteFileW(LPCWSTR pwszFilename)
 
 
 
+#ifdef WITH_CONSOLE_OUTPUT_BUFFERING
+
+/*
+ *
+ * Console output buffering.
+ * Console output buffering.
+ * Console output buffering.
+ *
+ */
+
+
+/**
+ * Write a wide char string to the console.
+ *
+ * @param   pSandbox            The sandbox which output buffer to flush.
+ */
+static void kwSandboxConsoleWriteIt(PKWSANDBOX pSandbox, wchar_t const *pwcBuf, KU32 cwcToWrite)
+{
+    if (cwcToWrite > 0)
+    {
+        DWORD cwcWritten = 0;
+        if (WriteConsoleW(pSandbox->Combined.hOutput, pwcBuf, cwcToWrite, &cwcWritten, NULL))
+        {
+            if (cwcWritten == cwcToWrite)
+            { /* likely */ }
+            else
+            {
+                DWORD off = 0;
+                do
+                {
+                    off += cwcWritten;
+                    cwcWritten = 0;
+                }
+                while (   off < cwcToWrite
+                       && WriteConsoleW(pSandbox->Combined.hOutput, &pwcBuf[off], cwcToWrite - off, &cwcWritten, NULL));
+                kHlpAssert(off == cwcWritten);
+            }
+        }
+        else
+            kHlpAssertFailed();
+        pSandbox->Combined.cFlushes++;
+    }
+}
+
+
+/**
+ * Flushes the combined console output buffer.
+ *
+ * @param   pSandbox            The sandbox which output buffer to flush.
+ */
+static void kwSandboxConsoleFlushCombined(PKWSANDBOX pSandbox)
+{
+    if (pSandbox->Combined.cwcBuf > 0)
+    {
+        kwSandboxConsoleWriteIt(pSandbox, pSandbox->Combined.wszBuf, pSandbox->Combined.cwcBuf);
+        pSandbox->Combined.cwcBuf = 0;
+    }
+}
+
+
+/**
+ * For handling combined buffer overflow cases line by line.
+ *
+ * @param   pSandbox            The sandbox.
+ * @param   pwcBuf              What to add to the combined buffer.  Usually a
+ *                              line, unless we're really low on buffer space.
+ * @param   cwcBuf              The length of what to add.
+ * @param   fBrokenLine         Whether this is a broken line.
+ */
+static void kwSandboxConsoleAddToCombined(PKWSANDBOX pSandbox, wchar_t const *pwcBuf, KU32 cwcBuf, KBOOL fBrokenLine)
+{
+    if (fBrokenLine)
+        kwSandboxConsoleFlushCombined(pSandbox);
+    if (pSandbox->Combined.cwcBuf + cwcBuf > K_ELEMENTS(pSandbox->Combined.wszBuf))
+    {
+        kwSandboxConsoleFlushCombined(pSandbox);
+        kwSandboxConsoleWriteIt(pSandbox, pwcBuf, cwcBuf);
+    }
+    else
+    {
+        memcpy(&pSandbox->Combined.wszBuf[pSandbox->Combined.cwcBuf], pwcBuf, cwcBuf * sizeof(wchar_t));
+        pSandbox->Combined.cwcBuf += cwcBuf;
+    }
+}
+
+
+/**
+ * Called to final flush a line buffer via the combined buffer (if applicable).
+ *
+ * @param   pSandbox            The sandbox.
+ * @param   pLineBuf            The line buffer.
+ */
+static void kwSandboxConsoleFinalFlushLineBuf(PKWSANDBOX pSandbox, PKWCONSOLEOUTPUTLINE pLineBuf)
+{
+    if (pLineBuf->cwcBuf > 0)
+    {
+        if (pLineBuf->fIsConsole)
+        {
+            if (pLineBuf->cwcBuf < pLineBuf->cwcBufAlloc)
+            {
+                pLineBuf->pwcBuf[pLineBuf->cwcBuf++] = '\n';
+                kwSandboxConsoleAddToCombined(pSandbox, pLineBuf->pwcBuf, pLineBuf->cwcBuf, K_FALSE /*fBrokenLine*/);
+            }
+            else
+            {
+                kwSandboxConsoleAddToCombined(pSandbox, pLineBuf->pwcBuf, pLineBuf->cwcBuf, K_TRUE /*fBrokenLine*/);
+                kwSandboxConsoleAddToCombined(pSandbox, L"\n", 1, K_TRUE /*fBrokenLine*/);
+            }
+            pLineBuf->cwcBuf = 0;
+        }
+        else
+        {
+            kHlpAssertFailed();
+        }
+    }
+}
+
+
+/**
+ * Called at the end of sandboxed execution to flush both stream buffers.
+ *
+ * @param   pSandbox            The sandbox.
+ */
+static void kwSandboxConsoleFlushAll(PKWSANDBOX pSandbox)
+{
+    /*
+     * First do the cl.exe source file supression trick, if applicable.
+     */
+    if (   pSandbox->Combined.cwcBuf >= 3
+        && pSandbox->StdOut.cwcBuf == 0
+        && pSandbox->StdErr.cwcBuf == 0
+        && pSandbox->Combined.cFlushes == 0
+        && pSandbox->pTool->u.Sandboxed.enmHint == KWTOOLHINT_VISUAL_CPP_CL)
+    {
+        KI32    off = pSandbox->Combined.cwcBuf - 1;
+        if (pSandbox->Combined.wszBuf[off] == '\n')
+        {
+            KBOOL fOk = K_TRUE;
+            while (off-- > 0)
+            {
+                wchar_t const wc = pSandbox->Combined.wszBuf[off];
+                if (iswalnum(wc) || wc == '.' || wc == ' ' || wc == '_' || wc == '-')
+                { /* likely */ }
+                else
+                {
+                    fOk = K_FALSE;
+                    break;
+                }
+            }
+            if (fOk)
+            {
+                pSandbox->Combined.cwcBuf = 0;
+                return;
+            }
+        }
+    }
+
+    /*
+     * Flush the two line buffer, the the combined buffer.
+     */
+    kwSandboxConsoleFinalFlushLineBuf(pSandbox, &pSandbox->StdErr);
+    kwSandboxConsoleFinalFlushLineBuf(pSandbox, &pSandbox->StdOut);
+    kwSandboxConsoleFlushCombined(pSandbox);
+}
+
+
+/**
+ * Writes a string to the given output stream.
+ *
+ * @param   pSandbox            The sandbox.
+ * @param   pLineBuf            The line buffer for the output stream.
+ * @param   pwcBuffer           The buffer to write.
+ * @param   cwcToWrite          The number of wchar_t's in the buffer.
+ */
+static void kwSandboxConsoleWriteW(PKWSANDBOX pSandbox, PKWCONSOLEOUTPUTLINE pLineBuf, wchar_t const *pwcBuffer, KU32 cwcToWrite)
+{
+    if (cwcToWrite > 0)
+    {
+        /*
+         * First, find the start of the last incomplete line so we can figure
+         * out how much line buffering we need to do.
+         */
+        KU32 cchLastIncompleteLine;
+        KU32 offLastIncompleteLine = cwcToWrite;
+        while (   offLastIncompleteLine > 0
+               && pwcBuffer[offLastIncompleteLine - 1] != '\n')
+            offLastIncompleteLine--;
+        cchLastIncompleteLine = cwcToWrite - offLastIncompleteLine;
+
+        /* Was there anything to line buffer? */
+        if (offLastIncompleteLine < cwcToWrite)
+        {
+            /* Need to grow the line buffer? */
+            KU32 cwcNeeded = offLastIncompleteLine != 0 ? offLastIncompleteLine : cchLastIncompleteLine + pLineBuf->cwcBuf;
+            if (cwcNeeded > pLineBuf->cwcBufAlloc)
+            {
+                void *pvNew;
+                KU32  cwcNew = !pLineBuf->cwcBufAlloc ? 1024 : pLineBuf->cwcBufAlloc * 2;
+                while (cwcNew < cwcNeeded)
+                    cwcNew *= 2;
+                pvNew = kHlpRealloc(pLineBuf->pwcBuf, cwcNew * sizeof(wchar_t));
+                if (pvNew)
+                {
+                    pLineBuf->pwcBuf = (wchar_t *)pvNew;
+                    pLineBuf->cwcBufAlloc = cwcNew;
+                }
+                else
+                {
+                    pvNew = kHlpRealloc(pLineBuf->pwcBuf, cwcNeeded * sizeof(wchar_t));
+                    if (pvNew)
+                    {
+                        pLineBuf->pwcBuf = (wchar_t *)pvNew;
+                        pLineBuf->cwcBufAlloc = cwcNeeded;
+                    }
+                    else
+                    {
+                        /* This isn't perfect, but it will have to do for now. */
+                        if (pLineBuf->cwcBuf > 0)
+                        {
+                            kwSandboxConsoleAddToCombined(pSandbox, pLineBuf->pwcBuf, pLineBuf->cwcBuf, K_TRUE /*fBrokenLine*/);
+                            pLineBuf->cwcBuf = 0;
+                        }
+                        kwSandboxConsoleAddToCombined(pSandbox, pwcBuffer, cwcToWrite, K_TRUE /*fBrokenLine*/);
+                        return;
+                    }
+                }
+            }
+
+            /*
+             * Handle the case where we only add to the line buffer.
+             */
+            if (offLastIncompleteLine == 0)
+            {
+                memcpy(&pLineBuf->pwcBuf[pLineBuf->cwcBuf], pwcBuffer, cwcToWrite * sizeof(wchar_t));
+                pLineBuf->cwcBuf += cwcToWrite;
+                return;
+            }
+        }
+
+        /*
+         * If there is sufficient combined buffer to handle this request, this are rather simple.
+         */
+        if (pLineBuf->cwcBuf + cchLastIncompleteLine <= K_ELEMENTS(pSandbox->Combined.wszBuf))
+        {
+            if (pLineBuf->cwcBuf > 0)
+            {
+                memcpy(&pSandbox->Combined.wszBuf[pSandbox->Combined.cwcBuf],
+                       pLineBuf->pwcBuf, pLineBuf->cwcBuf * sizeof(wchar_t));
+                pSandbox->Combined.cwcBuf += pLineBuf->cwcBuf;
+                pLineBuf->cwcBuf = 0;
+            }
+
+            memcpy(&pSandbox->Combined.wszBuf[pSandbox->Combined.cwcBuf],
+                   pwcBuffer, offLastIncompleteLine * sizeof(wchar_t));
+            pSandbox->Combined.cwcBuf += offLastIncompleteLine;
+        }
+        else
+        {
+            /*
+             * Do line-by-line processing of the input, flusing the combined buffer
+             * when it becomes necessary.  We may have to write lines
+             */
+            KU32 off = 0;
+            KU32 offNextLine = 0;
+
+            /* If there is buffered chars, we handle the first line outside the
+               main loop.  We must try our best outputting it as a complete line. */
+            if (pLineBuf->cwcBuf > 0)
+            {
+                while (offNextLine < cwcToWrite && pwcBuffer[offNextLine] != '\n')
+                    offNextLine++;
+                offNextLine++;
+                kHlpAssert(offNextLine <= offLastIncompleteLine);
+
+                if (pLineBuf->cwcBuf + offNextLine + pSandbox->Combined.cwcBuf <= K_ELEMENTS(pSandbox->Combined.wszBuf))
+                {
+                    memcpy(&pSandbox->Combined.wszBuf[pSandbox->Combined.cwcBuf],
+                           pLineBuf->pwcBuf, pLineBuf->cwcBuf * sizeof(wchar_t));
+                    pSandbox->Combined.cwcBuf += pLineBuf->cwcBuf;
+                    pLineBuf->cwcBuf = 0;
+
+                    memcpy(&pSandbox->Combined.wszBuf[pSandbox->Combined.cwcBuf], pwcBuffer, offNextLine * sizeof(wchar_t));
+                    pSandbox->Combined.cwcBuf += offNextLine;
+                }
+                else
+                {
+                    KU32 cwcLeft = pLineBuf->cwcBufAlloc - pLineBuf->cwcBuf;
+                    if (cwcLeft > 0)
+                    {
+                        KU32 cwcCopy = K_MIN(cwcLeft, offNextLine);
+                        memcpy(&pLineBuf->pwcBuf[pLineBuf->cwcBuf], pwcBuffer, cwcCopy * sizeof(wchar_t));
+                        pLineBuf->cwcBuf += cwcCopy;
+                        off += cwcCopy;
+                    }
+                    if (pLineBuf->cwcBuf > 0)
+                    {
+                        kwSandboxConsoleAddToCombined(pSandbox, pLineBuf->pwcBuf, pLineBuf->cwcBuf, K_TRUE /*fBrokenLine*/);
+                        pLineBuf->cwcBuf = 0;
+                    }
+                    if (off < offNextLine)
+                        kwSandboxConsoleAddToCombined(pSandbox, &pwcBuffer[off], offNextLine - off, K_TRUE /*fBrokenLine*/);
+                }
+                off = offNextLine;
+            }
+
+            /* Deal with the remaining lines */
+            while (off < offLastIncompleteLine)
+            {
+                while (offNextLine < offLastIncompleteLine && pwcBuffer[offNextLine] != '\n')
+                    offNextLine++;
+                offNextLine++;
+                kHlpAssert(offNextLine <= offLastIncompleteLine);
+                kwSandboxConsoleAddToCombined(pSandbox, &pwcBuffer[off], offNextLine - off, K_FALSE /*fBrokenLine*/);
+                off = offNextLine;
+            }
+        }
+
+        /*
+         * Buffer any remaining incomplete line chars.
+         */
+        if (offLastIncompleteLine < cwcToWrite)
+        {
+            memcpy(&pLineBuf->pwcBuf[0], &pwcBuffer[offLastIncompleteLine], cchLastIncompleteLine * sizeof(wchar_t));
+            pLineBuf->cwcBuf = cchLastIncompleteLine;
+        }
+    }
+}
+
+
+/**
+ * Worker for WriteConsoleA and WriteFile.
+ *
+ * @param   pSandbox            The sandbox.
+ * @param   pLineBuf            The line buffer.
+ * @param   pchBuffer           What to write.
+ * @param   cchToWrite          How much to write.
+ */
+static void kwSandboxConsoleWriteA(PKWSANDBOX pSandbox, PKWCONSOLEOUTPUTLINE pLineBuf, const char *pchBuffer, KU32 cchToWrite)
+{
+    /*
+     * Convert it to wide char and use the 'W' to do the work.
+     */
+    int         cwcRet;
+    KU32        cwcBuf = cchToWrite * 2 + 1;
+    wchar_t    *pwcBufFree = NULL;
+    wchar_t    *pwcBuf;
+
+    if (cwcBuf <= 4096)
+        pwcBuf = alloca(cwcBuf * sizeof(wchar_t));
+    else
+        pwcBuf = pwcBufFree = kHlpAlloc(cwcBuf * sizeof(wchar_t));
+
+    cwcRet = MultiByteToWideChar(pSandbox->Combined.uCodepage, 0/*dwFlags*/, pchBuffer, cchToWrite, pwcBuf, cwcBuf);
+    if (cwcRet > 0)
+         kwSandboxConsoleWriteW(pSandbox, pLineBuf, pwcBuf, cwcRet);
+    else
+    {
+        DWORD cchWritten;
+        kHlpAssertFailed();
+
+        /* Flush the line buffer and combined buffer before calling WriteConsoleA. */
+        if (pLineBuf->cwcBuf > 0)
+        {
+            kwSandboxConsoleAddToCombined(pSandbox, pLineBuf->pwcBuf, pLineBuf->cwcBuf, K_TRUE /*fBroken*/);
+            pLineBuf->cwcBuf = 0;
+        }
+        kwSandboxConsoleFlushCombined(pSandbox);
+
+        if (WriteConsoleA(pLineBuf->hBackup, pchBuffer, cchToWrite, &cchWritten, NULL /*pvReserved*/))
+        {
+            if (cchWritten >= cchToWrite)
+            { /* likely */ }
+            else
+            {
+                KU32 off = 0;
+                do
+                {
+                    off += cchWritten;
+                    cchWritten = 0;
+                } while (   off < cchToWrite
+                         && WriteConsoleA(pLineBuf->hBackup, &pchBuffer[off], cchToWrite - off, &cchWritten, NULL));
+            }
+        }
+    }
+
+    if (pwcBufFree)
+        kHlpFree(pwcBufFree);
+}
+
+
+/** Kernel32 - WriteConsoleA  */
+BOOL WINAPI kwSandbox_Kernel32_WriteConsoleA(HANDLE hConOutput, CONST VOID *pvBuffer, DWORD cbToWrite, PDWORD pcbWritten,
+                                             PVOID pvReserved)
+{
+    BOOL                    fRc;
+    PKWCONSOLEOUTPUTLINE    pLineBuf;
+    kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
+
+    if (hConOutput == g_Sandbox.StdErr.hOutput)
+        pLineBuf = &g_Sandbox.StdErr;
+    else
+        pLineBuf = &g_Sandbox.StdOut;
+    if (pLineBuf->fIsConsole)
+    {
+        kwSandboxConsoleWriteA(&g_Sandbox, pLineBuf, (char const *)pvBuffer, cbToWrite);
+
+        KWFS_LOG(("WriteConsoleA: %p, %p LB %#x (%*.*s), %p, %p -> TRUE [cached]\n",
+                  hConOutput, pvBuffer, cbToWrite, cbToWrite, cbToWrite, pvBuffer, pcbWritten, pvReserved));
+        if (pcbWritten)
+            *pcbWritten = cbToWrite;
+        fRc = TRUE;
+    }
+    else
+    {
+        fRc = WriteConsoleA(hConOutput, pvBuffer, cbToWrite, pcbWritten, pvReserved);
+        KWFS_LOG(("WriteConsoleA: %p, %p LB %#x (%*.*s), %p, %p -> %d !fallback!\n",
+                  hConOutput, pvBuffer, cbToWrite, cbToWrite, cbToWrite, pvBuffer, pcbWritten, pvReserved, fRc));
+    }
+    return fRc;
+}
+
+
+/** Kernel32 - WriteConsoleW  */
+BOOL WINAPI kwSandbox_Kernel32_WriteConsoleW(HANDLE hConOutput, CONST VOID *pvBuffer, DWORD cwcToWrite, PDWORD pcwcWritten,
+                                             PVOID pvReserved)
+{
+    BOOL                    fRc;
+    PKWCONSOLEOUTPUTLINE    pLineBuf;
+    kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
+
+    if (hConOutput == g_Sandbox.StdErr.hOutput)
+        pLineBuf = &g_Sandbox.StdErr;
+    else
+        pLineBuf = &g_Sandbox.StdOut;
+    if (pLineBuf->fIsConsole)
+    {
+        kwSandboxConsoleWriteW(&g_Sandbox, pLineBuf, (wchar_t const *)pvBuffer, cwcToWrite);
+
+        KWFS_LOG(("WriteConsoleW: %p, %p LB %#x (%*.*ls), %p, %p -> TRUE [cached]\n",
+                  hConOutput, pvBuffer, cwcToWrite, cwcToWrite, cwcToWrite, pvBuffer, pcwcWritten, pvReserved));
+        if (pcwcWritten)
+            *pcwcWritten = cwcToWrite;
+        fRc = TRUE;
+    }
+    else
+    {
+        fRc = WriteConsoleW(hConOutput, pvBuffer, cwcToWrite, pcwcWritten, pvReserved);
+        KWFS_LOG(("WriteConsoleW: %p, %p LB %#x (%*.*ls), %p, %p -> %d !fallback!\n",
+                  hConOutput, pvBuffer, cwcToWrite, cwcToWrite, cwcToWrite, pvBuffer, pcwcWritten, pvReserved, fRc));
+    }
+    return fRc;
+}
+
+#endif /* WITH_CONSOLE_OUTPUT_BUFFERING */
+
+
+
 /*
  *
  * Virtual memory leak prevension.
@@ -5518,7 +6256,10 @@ static PVOID WINAPI kwSandbox_Kernel32_VirtualAlloc(PVOID pvAddr, SIZE_T cb, DWO
     if (   g_Sandbox.pTool->u.Sandboxed.enmHint == KWTOOLHINT_VISUAL_CPP_CL
         && pvMem)
     {
-        PKWVIRTALLOC pTracker = g_Sandbox.pVirtualAllocHead;
+        PKWVIRTALLOC pTracker;
+        kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
+
+        pTracker = g_Sandbox.pVirtualAllocHead;
         while (   pTracker
                && (KUPTR)pvMem - (KUPTR)pTracker->pvAlloc >= pTracker->cbAlloc)
             pTracker = pTracker->pNext;
@@ -5547,6 +6288,7 @@ static BOOL WINAPI kwSandbox_Kernel32_VirtualFree(PVOID pvAddr, SIZE_T cb, DWORD
     KW_LOG(("VirtualFree: pvAddr=%p cb=%p type=%#x -> %d\n", pvAddr, cb, dwFreeType, fRc));
     if (g_Sandbox.pTool->u.Sandboxed.enmHint == KWTOOLHINT_VISUAL_CPP_CL)
     {
+        kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
         if (dwFreeType & MEM_RELEASE)
         {
             PKWVIRTALLOC pTracker = g_Sandbox.pVirtualAllocHead;
@@ -5576,6 +6318,66 @@ static BOOL WINAPI kwSandbox_Kernel32_VirtualFree(PVOID pvAddr, SIZE_T cb, DWORD
 }
 
 
+/** Kernel32 - HeapCreate / NtDll - RTlCreateHeap  */
+HANDLE WINAPI kwSandbox_Kernel32_HeapCreate(DWORD fOptions, SIZE_T cbInitial, SIZE_T cbMax)
+{
+    HANDLE hHeap;
+    kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
+
+    hHeap = HeapCreate(fOptions, cbInitial, cbMax);
+    if (hHeap != NULL)
+    {
+        DWORD dwErr = GetLastError();
+        PKWHEAP pTracker = (PKWHEAP)kHlpAlloc(sizeof(*pTracker));
+        if (pTracker)
+        {
+            pTracker->hHeap = hHeap;
+            pTracker->pNext = g_Sandbox.pHeapHead;
+            g_Sandbox.pHeapHead = pTracker;
+        }
+
+        SetLastError(dwErr);
+    }
+    return hHeap;
+
+}
+
+
+/** Kernel32 - HeapDestroy / NtDll - RTlDestroyHeap */
+BOOL WINAPI kwSandbox_Kernel32_HeapDestroy(HANDLE hHeap)
+{
+    BOOL fRc = HeapDestroy(hHeap);
+    KW_LOG(("HeapDestroy: hHeap=%p -> %d\n", hHeap, fRc));
+    kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
+    if (fRc)
+    {
+        PKWHEAP pTracker = g_Sandbox.pHeapHead;
+        if (pTracker)
+        {
+            if (pTracker->hHeap == hHeap)
+                g_Sandbox.pHeapHead = pTracker->pNext;
+            else
+            {
+                PKWHEAP pPrev;
+                do
+                {
+                    pPrev = pTracker;
+                    pTracker = pTracker->pNext;
+                } while (pTracker && pTracker->hHeap == hHeap);
+                if (pTracker)
+                    pPrev->pNext = pTracker->pNext;
+            }
+            if (pTracker)
+                kHlpFree(pTracker);
+            else
+                KW_LOG(("HeapDestroy: pvAddr=%p not found!\n", hHeap));
+        }
+    }
+
+    return fRc;
+}
+
+
 
 /*
  *
@@ -5600,6 +6402,7 @@ DWORD WINAPI kwSandbox_Kernel32_FlsAlloc(PFLS_CALLBACK_FUNCTION pfnCallback)
         PKWLOCALSTORAGE pTracker = (PKWLOCALSTORAGE)kHlpAlloc(sizeof(*pTracker));
         if (pTracker)
         {
+            kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
             pTracker->idx = idxFls;
             pTracker->pNext = g_Sandbox.pFlsAllocHead;
             g_Sandbox.pFlsAllocHead = pTracker;
@@ -5616,7 +6419,10 @@ BOOL WINAPI kwSandbox_Kernel32_FlsFree(DWORD idxFls)
     KW_LOG(("FlsFree(%#x) -> %d\n", idxFls, fRc));
     if (fRc)
     {
-        PKWLOCALSTORAGE pTracker = g_Sandbox.pFlsAllocHead;
+        PKWLOCALSTORAGE pTracker;
+        kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
+
+        pTracker = g_Sandbox.pFlsAllocHead;
         if (pTracker)
         {
             if (pTracker->idx == idxFls)
@@ -5679,6 +6485,7 @@ static BOOL WINAPI kwSandbox_Advapi32_CryptCreateHash(HCRYPTPROV hProv, ALG_ID i
                     PKWHASHMD5 pHash = (PKWHASHMD5)kHlpAllocZ(sizeof(*pHash));
                     if (pHash)
                     {
+                        kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
                         pHash->uMagic        = KWHASHMD5_MAGIC;
                         pHash->cbHashed      = 0;
                         pHash->fGoneBad      = K_FALSE;
@@ -5722,6 +6529,7 @@ static BOOL WINAPI kwSandbox_Advapi32_CryptHashData(HCRYPTHASH hHash, CONST BYTE
 {
     BOOL        fRc;
     PKWHASHMD5  pHash = g_Sandbox.pHashHead;
+    kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
     while (pHash && (KUPTR)pHash != hHash)
         pHash = pHash->pNext;
     KWCRYPT_LOG(("CryptHashData(hHash=%p/%p, pbData=%p, cbData=%#x, dwFlags=%#x)\n",
@@ -5837,6 +6645,7 @@ static BOOL WINAPI kwSandbox_Advapi32_CryptGetHashParam(HCRYPTHASH hHash, DWORD
 {
     BOOL        fRc;
     PKWHASHMD5  pHash = g_Sandbox.pHashHead;
+    kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
     while (pHash && (KUPTR)pHash != hHash)
         pHash = pHash->pNext;
     if (pHash)
@@ -5994,6 +6803,7 @@ static BOOL WINAPI kwSandbox_Advapi32_CryptDestroyHash(HCRYPTHASH hHash)
     BOOL        fRc;
     PKWHASHMD5  pPrev = NULL;
     PKWHASHMD5  pHash = g_Sandbox.pHashHead;
+    kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
     while (pHash && (KUPTR)pHash != hHash)
     {
         pPrev = pHash;
@@ -6126,9 +6936,15 @@ KWREPLACEMENTFUNCTION const g_aSandboxReplacements[] =
     { TUPLE("DeleteFileW"),                 NULL,       (KUPTR)kwSandbox_Kernel32_DeleteFileW },
 #endif
 
+    { TUPLE("WriteConsoleA"),               NULL,       (KUPTR)kwSandbox_Kernel32_WriteConsoleA },
+    { TUPLE("WriteConsoleW"),               NULL,       (KUPTR)kwSandbox_Kernel32_WriteConsoleW },
+
     { TUPLE("VirtualAlloc"),                NULL,       (KUPTR)kwSandbox_Kernel32_VirtualAlloc },
     { TUPLE("VirtualFree"),                 NULL,       (KUPTR)kwSandbox_Kernel32_VirtualFree },
 
+    { TUPLE("HeapCreate"),                  NULL,       (KUPTR)kwSandbox_Kernel32_HeapCreate,       K_TRUE /*fOnlyExe*/ },
+    { TUPLE("HeapDestroy"),                 NULL,       (KUPTR)kwSandbox_Kernel32_HeapDestroy,      K_TRUE /*fOnlyExe*/ },
+
     { TUPLE("FlsAlloc"),                    NULL,       (KUPTR)kwSandbox_Kernel32_FlsAlloc },
     { TUPLE("FlsFree"),                     NULL,       (KUPTR)kwSandbox_Kernel32_FlsFree },
 
@@ -6151,6 +6967,10 @@ KWREPLACEMENTFUNCTION const g_aSandboxReplacements[] =
     { TUPLE("_amsg_exit"),                  NULL,       (KUPTR)kwSandbox_msvcrt__amsg_exit },
     { TUPLE("terminate"),                   NULL,       (KUPTR)kwSandbox_msvcrt_terminate },
 
+    { TUPLE("onexit"),                      NULL,       (KUPTR)kwSandbox_msvcrt__onexit,            K_TRUE /*fOnlyExe*/ },
+    { TUPLE("_onexit"),                     NULL,       (KUPTR)kwSandbox_msvcrt__onexit,            K_TRUE /*fOnlyExe*/ },
+    { TUPLE("atexit"),                      NULL,       (KUPTR)kwSandbox_msvcrt_atexit,             K_TRUE /*fOnlyExe*/ },
+
     { TUPLE("_beginthread"),                NULL,       (KUPTR)kwSandbox_msvcrt__beginthread },
     { TUPLE("_beginthreadex"),              NULL,       (KUPTR)kwSandbox_msvcrt__beginthreadex },
 
@@ -6240,6 +7060,9 @@ KWREPLACEMENTFUNCTION const g_aSandboxNativeReplacements[] =
 #endif
     { TUPLE("SetConsoleCtrlHandler"),       NULL,       (KUPTR)kwSandbox_Kernel32_SetConsoleCtrlHandler },
 
+    { TUPLE("WriteConsoleA"),               NULL,       (KUPTR)kwSandbox_Kernel32_WriteConsoleA },
+    { TUPLE("WriteConsoleW"),               NULL,       (KUPTR)kwSandbox_Kernel32_WriteConsoleW },
+
 #ifdef WITH_HASH_MD5_CACHE
     { TUPLE("CryptCreateHash"),             NULL,       (KUPTR)kwSandbox_Advapi32_CryptCreateHash },
     { TUPLE("CryptHashData"),               NULL,       (KUPTR)kwSandbox_Advapi32_CryptHashData },
@@ -6552,6 +7375,12 @@ static int kwSandboxInit(PKWSANDBOX pSandbox, PKWTOOL pTool,
     pSandbox->idMainThread  = GetCurrentThreadId();
     pSandbox->pgmptr        = (char *)pTool->pszPath;
     pSandbox->wpgmptr       = (wchar_t *)pTool->pwszPath;
+#ifdef WITH_CONSOLE_OUTPUT_BUFFERING
+    pSandbox->StdOut.cwcBuf = 0;
+    pSandbox->StdErr.cwcBuf = 0;
+    pSandbox->Combined.cwcBuf = 0;
+    pSandbox->Combined.cFlushes = 0;
+#endif
     pSandbox->cArgs         = cArgs;
     pSandbox->papszArgs     = (char **)papszArgs;
     pSandbox->pszCmdLine    = kwSandboxInitCmdLineFromArgv(cArgs, papszArgs, fWatcomBrainDamange, &cbCmdLine);
@@ -6652,13 +7481,40 @@ static void kwSandboxCleanupLate(PKWSANDBOX pSandbox)
 {
     PROCESS_MEMORY_COUNTERS     MemInfo;
     PKWVIRTALLOC                pTracker;
+    PKWHEAP                     pHeap;
     PKWLOCALSTORAGE             pLocalStorage;
 #ifdef WITH_HASH_MD5_CACHE
     PKWHASHMD5                  pHash;
 #endif
 #ifdef WITH_TEMP_MEMORY_FILES
     PKWFSTEMPFILE               pTempFile;
+#endif
+    PKWEXITCALLACK              pExitCallback;
+
+    /* Do exit callback first. */
+    pExitCallback = g_Sandbox.pExitCallbackHead;
+    g_Sandbox.pExitCallbackHead = NULL;
+    while (pExitCallback)
+    {
+        PKWEXITCALLACK  pNext = pExitCallback->pNext;
+        KW_LOG(("kwSandboxCleanupLate: calling %p %sexit handler\n",
+                pExitCallback->pfnCallback, pExitCallback->fAtExit ? "at" : "_on"));
+        __try
+        {
+            pExitCallback->pfnCallback();
+        }
+        __except (EXCEPTION_EXECUTE_HANDLER)
+        {
+            KW_LOG(("kwSandboxCleanupLate: %sexit handler %p threw an exception!\n",
+                    pExitCallback->fAtExit ? "at" : "_on", pExitCallback->pfnCallback));
+            kHlpAssertFailed();
+        }
+        kHlpFree(pExitCallback);
+        pExitCallback = pNext;
+    }
+
 
+#ifdef WITH_TEMP_MEMORY_FILES
     /* The temporary files aren't externally visible, they're all in memory. */
     pTempFile = pSandbox->pTempFileHead;
     pSandbox->pTempFileHead = NULL;
@@ -6688,6 +7544,17 @@ static void kwSandboxCleanupLate(PKWSANDBOX pSandbox)
         pTracker = pNext;
     }
 
+    /* Free left behind HeapCreate leaks. */
+    pHeap = g_Sandbox.pHeapHead;
+    g_Sandbox.pHeapHead = NULL;
+    while (pHeap != NULL)
+    {
+        PKWHEAP pNext = pHeap->pNext;
+        KW_LOG(("Freeing HeapCreate leak %p\n", pHeap->hHeap));
+        HeapDestroy(pHeap->hHeap);
+        pHeap = pNext;
+    }
+
     /* Free left behind FlsAlloc leaks. */
     pLocalStorage = g_Sandbox.pFlsAllocHead;
     g_Sandbox.pFlsAllocHead = NULL;
@@ -6884,7 +7751,13 @@ static int kwSandboxExec(PKWSANDBOX pSandbox, PKWTOOL pTool, KU32 cArgs, const c
         else
             rcExit = 42 + 4;
 
-        /* Clean up essential bits only, the rest is done after we've replied to kmk. */
+        /*
+         * Flush and clean up the essential bits only, postpone whatever we
+         * can till after we've replied to kmk.
+         */
+#ifdef WITH_CONSOLE_OUTPUT_BUFFERING
+        kwSandboxConsoleFlushAll(&g_Sandbox);
+#endif
         kwSandboxCleanup(&g_Sandbox);
     }
     else
@@ -7375,6 +8248,11 @@ int main(int argc, char **argv)
 #if defined(KBUILD_OS_WINDOWS) && defined(KBUILD_ARCH_X86)
     PVOID           pvVecXcptHandler = AddVectoredExceptionHandler(0 /*called last*/, kwSandboxVecXcptEmulateChained);
 #endif
+#ifdef WITH_CONSOLE_OUTPUT_BUFFERING
+    HANDLE                          hCurProc       = GetCurrentProcess();
+    PPEB                            pPeb           = kwSandboxGetProcessEnvironmentBlock();
+    PMY_RTL_USER_PROCESS_PARAMETERS pProcessParams = (PMY_RTL_USER_PROCESS_PARAMETERS)pPeb->ProcessParameters;
+#endif
 
     /*
      * Register our Control-C and Control-Break handlers.
@@ -7399,6 +8277,40 @@ int main(int argc, char **argv)
     if (pszTmp && *pszTmp != '\0')
         kFsCacheSetupCustomRevisionForTree(g_pFsCache, kFsCacheLookupA(g_pFsCache, pszTmp, &enmIgnored));
 
+#ifdef WITH_CONSOLE_OUTPUT_BUFFERING
+    /*
+     * Get and duplicate the console handles.
+     */
+    g_Sandbox.StdOut.hOutput = pProcessParams->StandardOutput;
+    if (!DuplicateHandle(hCurProc, pProcessParams->StandardOutput, hCurProc, &g_Sandbox.StdOut.hBackup,
+                         GENERIC_WRITE, FALSE /*fInherit*/, DUPLICATE_SAME_ACCESS))
+        kHlpAssertFailedStmt(g_Sandbox.StdOut.hBackup = pProcessParams->StandardOutput);
+    g_Sandbox.StdOut.fIsConsole = GetFileType(g_Sandbox.StdOut.hOutput) == FILE_TYPE_CHAR;
+
+    g_Sandbox.StdErr.hOutput = pProcessParams->StandardError;
+    if (!DuplicateHandle(hCurProc, pProcessParams->StandardError, hCurProc, &g_Sandbox.StdErr.hBackup,
+                         GENERIC_WRITE, FALSE /*fInherit*/, DUPLICATE_SAME_ACCESS))
+        kHlpAssertFailedStmt(g_Sandbox.StdErr.hBackup = pProcessParams->StandardError);
+    g_Sandbox.StdErr.fIsConsole = GetFileType(g_Sandbox.StdErr.hOutput) == FILE_TYPE_CHAR;
+
+    if (g_Sandbox.StdErr.fIsConsole)
+    {
+        g_Sandbox.Combined.hOutput   = g_Sandbox.StdErr.hBackup;
+        g_Sandbox.Combined.uCodepage = GetConsoleCP();
+    }
+    else if (g_Sandbox.StdOut.fIsConsole)
+    {
+        g_Sandbox.Combined.hOutput   = g_Sandbox.StdOut.hBackup;
+        g_Sandbox.Combined.uCodepage = GetConsoleCP();
+    }
+    else
+    {
+        g_Sandbox.Combined.hOutput   = INVALID_HANDLE_VALUE;
+        g_Sandbox.Combined.uCodepage = CP_ACP;
+    }
+#endif
+
+
     /*
      * Parse arguments.
      */
diff --git a/src/kmk/Makefile.kmk b/src/kmk/Makefile.kmk
index 80c5168..11fe58f 100644
--- a/src/kmk/Makefile.kmk
+++ b/src/kmk/Makefile.kmk
@@ -1,4 +1,4 @@
-# $Id: Makefile.kmk 2886 2016-09-06 14:31:46Z bird $
+# $Id: Makefile.kmk 2907 2016-09-09 22:33:26Z bird $
 ## @file
 # Sub-makefile for kmk / GNU Make.
 #
@@ -57,7 +57,7 @@ TEMPLATE_BIN-KMK_INCS = $(kmk_0_OUTDIR) . $(TEMPLATE_BIN-THREADED_INCS)
 ifneq ($(KBUILD_TARGET),os2)
  TEMPLATE_BIN-KMK_INCS += glob
 endif
-TEMPLATE_BIN-KMK_LIBS = $(TEMPLATE_BIN-THREADED_LIBS) $(kmkmissing_1_TARGET) $(LIB_KUTIL)
+TEMPLATE_BIN-KMK_LIBS = $(LIB_KUTIL) $(TEMPLATE_BIN-THREADED_LIBS) $(kmkmissing_1_TARGET) $(LIB_KUTIL)
 ifdef ELECTRIC_HEAP # for electric heap (see electric.c) - windows only.
 ifeq ($(KBUILD_TARGET),win)
  TEMPLATE_BIN-KMK_CFLAGS = $(TEMPLATE_BIN-THREADED_CFLAGS) /FI$(kmk_DEFPATH)/electric.h -DELECTRIC_HEAP=1
@@ -281,7 +281,7 @@ kmk_SOURCES += \
 	kmkbuiltin/printf.c \
 	kmkbuiltin/rm.c \
 	kmkbuiltin/rmdir.c \
-	kmkbuiltin/kSubmit.c \
+	$(if-expr $(KBUILD_TARGET) == win,kmkbuiltin/kSubmit.c) \
 	kmkbuiltin/sleep.c \
 	kmkbuiltin/test.c
 
diff --git a/src/kmk/kmkbuiltin.h b/src/kmk/kmkbuiltin.h
index 04e964b..8c3a8a3 100644
--- a/src/kmk/kmkbuiltin.h
+++ b/src/kmk/kmkbuiltin.h
@@ -1,4 +1,4 @@
-/* $Id: kmkbuiltin.h 2846 2016-08-30 12:48:33Z bird $ */
+/* $Id: kmkbuiltin.h 2899 2016-09-09 09:03:57Z bird $ */
 /** @file
  * kMk Builtin command handling.
  */
@@ -36,6 +36,7 @@
 
 #include "kbuild_version.h"
 
+struct child;
 int kmk_builtin_command(const char *pszCmd, struct child *pChild, char ***ppapszArgvToSpawn, pid_t *pPidSpawned);
 int kmk_builtin_command_parsed(int argc, char **argv, struct child *pChild, char ***ppapszArgvToSpawn, pid_t *pPidSpawned);
 
diff --git a/src/kmk/kmkbuiltin/cat.c b/src/kmk/kmkbuiltin/cat.c
index 2e4e7ed..d9fc0a2 100644
--- a/src/kmk/kmkbuiltin/cat.c
+++ b/src/kmk/kmkbuiltin/cat.c
@@ -80,6 +80,14 @@ __FBSDID("$FreeBSD: src/bin/cat/cat.c,v 1.32 2005/01/10 08:39:20 imp Exp $");
 #include "kmkbuiltin.h"
 
 
+#ifdef KBUILD_OS_WINDOWS
+/* This is a trick to seriuosly speed up console output windows. */
+# undef write
+# define write maybe_con_write
+extern ssize_t maybe_con_write(int, void const *, size_t);
+#endif
+
+
 int bflag, eflag, nflag, sflag, tflag, vflag;
 /*int rval;*/
 const char *filename;
@@ -119,6 +127,8 @@ kmk_builtin_cat(int argc, char *argv[], char **envp)
 
 #ifdef kmk_builtin_cat /* kmk did this already. */
 	setlocale(LC_CTYPE, "");
+#else
+	fflush(stdout);
 #endif
 
 	while ((ch = getopt_long(argc, argv, "benstuv", long_options, NULL)) != -1)
@@ -287,7 +297,7 @@ cook_cat(FILE *fp)
 static int
 raw_cat(int rfd)
 {
-	int off, wfd;
+	int off, wfd = fileno(stdout);
 	ssize_t nr, nw;
 	static size_t bsize;
 	static char *buf = NULL;
@@ -297,8 +307,8 @@ raw_cat(int rfd)
 	if (buf == NULL) {
 		if (fstat(wfd, &sbuf))
 			return err(1, "%s", filename);
-#ifdef _MSC_VER
-		bsize = 1024;
+#ifdef KBUILD_OS_WINDOWS
+		bsize = 16384;
 #else
 		bsize = MAX(sbuf.st_blksize, 1024);
 #endif
diff --git a/src/kmk/kmkbuiltin/err.c b/src/kmk/kmkbuiltin/err.c
index 230b2fe..90d99e4 100644
--- a/src/kmk/kmkbuiltin/err.c
+++ b/src/kmk/kmkbuiltin/err.c
@@ -1,10 +1,10 @@
-/* $Id: err.c 2413 2010-09-11 17:43:04Z bird $ */
+/* $Id: err.c 2911 2016-09-10 11:16:59Z bird $ */
 /** @file
  * Override err.h so we get the program name right.
  */
 
 /*
- * Copyright (c) 2005-2010 knut st. osmundsen <bird-kBuild-spamx at anduin.net>
+ * Copyright (c) 2005-2016 knut st. osmundsen <bird-kBuild-spamx at anduin.net>
  *
  * This file is part of kBuild.
  *
@@ -33,6 +33,13 @@
 #include <errno.h>
 #include "err.h"
 
+#ifdef KBUILD_OS_WINDOWS
+/* This is a trick to speed up console output on windows. */
+# undef fwrite
+# define fwrite maybe_con_fwrite
+extern size_t maybe_con_fwrite(void const *, size_t, size_t, FILE *);
+#endif
+
 
 /** The current program name. */
 const char *g_progname = "kmk";
@@ -42,6 +49,34 @@ int err(int eval, const char *fmt, ...)
 {
     va_list args;
     int error = errno;
+
+    /* stderr is unbuffered, so try format the whole message and print it in
+       one go so it won't be split by other output. */
+    char szMsg[4096];
+    int cchMsg = snprintf(szMsg, sizeof(szMsg), "%s: ", g_progname);
+    if (cchMsg < sizeof(szMsg) - 1 && cchMsg > 0)
+    {
+        int cchMsg2;
+        va_start(args, fmt);
+        cchMsg += cchMsg2 = vsnprintf(&szMsg[cchMsg], sizeof(szMsg) - cchMsg, fmt, args);
+        va_end(args);
+
+        if (   cchMsg < sizeof(szMsg) - 1
+            && cchMsg2 >= 0)
+        {
+            cchMsg += cchMsg2 = snprintf(&szMsg[cchMsg], sizeof(szMsg) - cchMsg, ": %s\n", strerror(error));
+            if (   cchMsg < sizeof(szMsg) - 1
+                && cchMsg2 >= 0)
+            {
+                fwrite(szMsg, cchMsg, 1, stderr);
+                return eval;
+            }
+
+        }
+
+    }
+
+    /* fallback */
     fprintf(stderr, "%s: ", g_progname);
     va_start(args, fmt);
     vfprintf(stderr, fmt, args);
@@ -55,6 +90,29 @@ int err(int eval, const char *fmt, ...)
 int errx(int eval, const char *fmt, ...)
 {
     va_list args;
+
+    /* stderr is unbuffered, so try format the whole message and print it in
+       one go so it won't be split by other output. */
+    char szMsg[4096];
+    int cchMsg = snprintf(szMsg, sizeof(szMsg), "%s: ", g_progname);
+    if (cchMsg < sizeof(szMsg) - 1 && cchMsg > 0)
+    {
+        int cchMsg2;
+        va_start(args, fmt);
+        cchMsg += cchMsg2 = vsnprintf(&szMsg[cchMsg], sizeof(szMsg) - cchMsg, fmt, args);
+        va_end(args);
+
+        if (   cchMsg < sizeof(szMsg) - 1
+            && cchMsg2 >= 0)
+        {
+            szMsg[cchMsg++] = '\n';
+            fwrite(szMsg, cchMsg, 1, stderr);
+            return eval;
+        }
+
+    }
+
+    /* fallback */
     fprintf(stderr, "%s: ", g_progname);
     va_start(args, fmt);
     vfprintf(stderr, fmt, args);
@@ -68,6 +126,33 @@ void warn(const char *fmt, ...)
 {
     int error = errno;
     va_list args;
+
+    /* stderr is unbuffered, so try format the whole message and print it in
+       one go so it won't be split by other output. */
+    char szMsg[4096];
+    int cchMsg = snprintf(szMsg, sizeof(szMsg), "%s: ", g_progname);
+    if (cchMsg < sizeof(szMsg) - 1 && cchMsg > 0)
+    {
+        int cchMsg2;
+        va_start(args, fmt);
+        cchMsg += cchMsg2 = vsnprintf(&szMsg[cchMsg], sizeof(szMsg) - cchMsg, fmt, args);
+        va_end(args);
+
+        if (   cchMsg < sizeof(szMsg) - 1
+            && cchMsg2 >= 0)
+        {
+            cchMsg += cchMsg2 = snprintf(&szMsg[cchMsg], sizeof(szMsg) - cchMsg, ": %s\n", strerror(error));
+            if (   cchMsg < sizeof(szMsg) - 1
+                && cchMsg2 >= 0)
+            {
+                fwrite(szMsg, cchMsg, 1, stderr);
+                return;
+            }
+
+        }
+    }
+
+    /* fallback */
     fprintf(stderr, "%s: ", g_progname);
     va_start(args, fmt);
     vfprintf(stderr, fmt, args);
@@ -78,6 +163,29 @@ void warn(const char *fmt, ...)
 void warnx(const char *fmt, ...)
 {
     va_list args;
+
+    /* stderr is unbuffered, so try format the whole message and print it in
+       one go so it won't be split by other output. */
+    char szMsg[4096];
+    int cchMsg = snprintf(szMsg, sizeof(szMsg), "%s: ", g_progname);
+    if (cchMsg < sizeof(szMsg) - 1 && cchMsg > 0)
+    {
+        int cchMsg2;
+        va_start(args, fmt);
+        cchMsg += cchMsg2 = vsnprintf(&szMsg[cchMsg], sizeof(szMsg) - cchMsg, fmt, args);
+        va_end(args);
+
+        if (   cchMsg < sizeof(szMsg) - 1
+            && cchMsg2 >= 0)
+        {
+            szMsg[cchMsg++] = '\n';
+            fwrite(szMsg, cchMsg, 1, stderr);
+            return;
+        }
+
+    }
+
+    /* fallback */
     fprintf(stderr, "%s: ", g_progname);
     va_start(args, fmt);
     vfprintf(stderr, fmt, args);
diff --git a/src/kmk/kmkbuiltin/mscfakes.c b/src/kmk/kmkbuiltin/mscfakes.c
index b8e33c7..b820dd8 100644
--- a/src/kmk/kmkbuiltin/mscfakes.c
+++ b/src/kmk/kmkbuiltin/mscfakes.c
@@ -1,4 +1,4 @@
-/* $Id: mscfakes.c 2759 2015-01-28 16:14:00Z bird $ */
+/* $Id: mscfakes.c 2901 2016-09-09 15:10:24Z bird $ */
 /** @file
  * Fake Unix stuff for MSC.
  */
@@ -633,11 +633,11 @@ int vasprintf(char **strp, const char *fmt, va_list va)
 
 #ifdef va_copy
         va_copy(va2, va);
-        rc = snprintf(psz, cb, fmt, va2);
+        rc = vsnprintf(psz, cb, fmt, va2);
         va_end(vaCopy);
 #else
         va2 = va;
-        rc = snprintf(psz, cb, fmt, va2);
+        rc = vsnprintf(psz, cb, fmt, va2);
 #endif
         if (rc < 0 || (size_t)rc < cb)
             break;
diff --git a/src/kmk/kmkbuiltin/printf.c b/src/kmk/kmkbuiltin/printf.c
index 36150e2..a27824b 100644
--- a/src/kmk/kmkbuiltin/printf.c
+++ b/src/kmk/kmkbuiltin/printf.c
@@ -75,6 +75,13 @@ __RCSID("$NetBSD: printf.c,v 1.31 2005/03/22 23:55:46 dsl Exp $");
 
 #include "../kmkbuiltin.h"
 
+#ifdef KBUILD_OS_WINDOWS
+/* This is a trick to speed up console output on windows. */
+# undef fwrite
+# define fwrite maybe_con_fwrite
+extern size_t maybe_con_fwrite(void const *, size_t, size_t, FILE *);
+#endif
+
 
 #ifdef __GNUC__
 #define ESCAPE '\e'
@@ -112,6 +119,7 @@ static char	*mklong(const char *, int);
 static void      check_conversion(const char *, const char *);
 static int	 usage(FILE *);
 
+static int	flush_buffer(void);
 static void	b_count(int);
 static void	b_output(int);
 static int	wrap_putchar(int ch);
@@ -126,6 +134,10 @@ static int	wrap_printf(const char *, ...);
 #include "../../bin/sh/bltin/bltin.h"
 #endif /* SHELL */
 
+/* Buffer the output because windows doesn't do line buffering of stdout. */
+static char 	g_achBuf[256];
+static size_t	g_cchBuf;
+
 #define PF(f, func) { \
 	if (fieldwidth != -1) { \
 		if (precision != -1) \
@@ -155,7 +167,7 @@ int kmk_builtin_printf(int argc, char *argv[], char **envp)
 	int rc;
 	int ch;
 
-	/* kmk: reset getopt and set progname */
+	/* kmk: reset getopt, set progname and reset buffer. */
 	g_progname = argv[0];
 	opterr = 1;
 	optarg = NULL;
@@ -224,6 +236,7 @@ static int common_printf(int argc, char *argv[])
 	b_fmt = NULL;
 	rval = 0;
 	gargv = NULL;
+	g_cchBuf = 0;
 
 	format = *argv;
 	gargv = ++argv;
@@ -271,6 +284,7 @@ static int common_printf(int argc, char *argv[])
 
 			ch = *fmt;
 			if (!ch) {
+				flush_buffer();
 				warnx("missing format character");
 				return (1);
 			}
@@ -353,20 +367,25 @@ static int common_printf(int argc, char *argv[])
 				break;
 			}
 			default:
+				flush_buffer();
 				warnx("%s: invalid directive", start);
 				return 1;
 			}
 			*fmt++ = ch;
 			*fmt = nextch;
 			/* escape if a \c was encountered */
-			if (rval & 0x100)
+			if (rval & 0x100) {
+				flush_buffer();
 				return rval & ~0x100;
+			}
 		}
 	} while (gargv != argv && *gargv);
 
+	flush_buffer();
 	return rval;
 }
 
+
 /* helper functions for conv_escape_str */
 
 static void
@@ -407,36 +426,105 @@ static int wrap_putchar(int ch)
 		return ch;
 	}
 #endif
-	return putchar(ch);
+	/* Buffered output. */
+	if (g_cchBuf + 1 < sizeof(g_achBuf)) {
+		g_achBuf[g_cchBuf++] = ch;
+	} else {
+		int rc = flush_buffer();
+		g_achBuf[g_cchBuf++] = ch;
+		if (rc)
+			return -1;
+	}
+	return 0;
 }
 
 static int wrap_printf(const char * fmt, ...)
 {
-	int rc;
+	ssize_t cchRet;
 	va_list va;
+	char *pszTmp;
 
+	va_start(va, fmt);
+	cchRet = vasprintf(&pszTmp, fmt, va);
+	va_end(va);
+	if (cchRet >= 0) {
 #ifndef kmk_builtin_printf
-	if (g_o) {
-		char *str;
-
-		va_start(va, fmt);
-		rc = vasprintf(&str, fmt, va);
-		va_end(va);
-		if (rc >= 0) {
-			g_o = variable_buffer_output(g_o, str, rc);
-			free(str);
+		if (g_o) {
+			g_o = variable_buffer_output(g_o, pszTmp, cchRet);
+		} else
+#endif
+		{
+			if (cchRet + g_cchBuf <= sizeof(g_achBuf)) {
+				/* We've got space in the buffer. */
+				memcpy(&g_achBuf[g_cchBuf], pszTmp, cchRet);
+				g_cchBuf += cchRet;
+			} else {
+				/* Try write out complete lines. */
+				const char *pszLeft = pszTmp;
+				ssize_t     cchLeft = cchRet;
+
+				while (cchLeft > 0) {
+					const char *pchNewLine = strchr(pszLeft, '\n');
+					ssize_t     cchLine    = pchNewLine ? pchNewLine - pszLeft + 1 : cchLeft;
+					if (g_cchBuf + cchLine <= sizeof(g_achBuf)) {
+						memcpy(&g_achBuf[g_cchBuf], pszLeft, cchLine);
+						g_cchBuf += cchLine;
+					} else {
+						if (flush_buffer() < 0) {
+							return -1;
+						}
+						if (fwrite(pszLeft, cchLine, 1, stdout) < 1) {
+							return -1;
+						}
+					}
+					pszLeft += cchLine;
+					cchLeft -= cchLine;
+				}
+			}
 		}
-		return rc;
+		free(pszTmp);
 	}
-#endif
+	return (int)cchRet;
+}
 
-	va_start(va, fmt);
-	rc = vprintf(fmt, va);
-	va_end(va);
-	return rc;
+/**
+ * Flushes the g_abBuf/g_cchBuf.
+ */
+static int flush_buffer(void)
+{
+    if (g_cchBuf > 0) {
+		ssize_t cchToWrite = g_cchBuf;
+		ssize_t cchWritten = fwrite(g_achBuf, 1, g_cchBuf, stdout);
+		g_cchBuf = 0;
+		if (cchWritten >= cchToWrite) {
+			/* likely */
+		} else {
+			ssize_t off = cchWritten;
+			if (cchWritten >= 0) {
+				off = cchWritten;
+			} else if (errno == EINTR) {
+				cchWritten = 0;
+			} else {
+				return -1;
+			}
+
+			while (off < cchToWrite) {
+				cchWritten = fwrite(&g_achBuf[off], 1, cchToWrite - off, stdout);
+				if (cchWritten > 0) {
+					off += cchWritten;
+				} else if (errno == EINTR) {
+					/* nothing */
+				} else {
+					return -1;
+				}
+			}
+		}
+    }
+    return 0;
 }
 
 
+
 /*
  * Print SysV echo(1) style escape string
  *	Halts processing string if a \c escape is encountered.
diff --git a/src/kmk/kmkbuiltin/solfakes.c b/src/kmk/kmkbuiltin/solfakes.c
index 2f4b818..6996ab4 100644
--- a/src/kmk/kmkbuiltin/solfakes.c
+++ b/src/kmk/kmkbuiltin/solfakes.c
@@ -1,4 +1,4 @@
-/* $Id: solfakes.c 2413 2010-09-11 17:43:04Z bird $ */
+/* $Id: solfakes.c 2901 2016-09-09 15:10:24Z bird $ */
 /** @file
  * Fake Unix stuff for Solaris.
  */
@@ -63,11 +63,11 @@ int vasprintf(char **strp, const char *fmt, va_list va)
 
 #ifdef va_copy
         va_copy(va2, va);
-        rc = snprintf(psz, cb, fmt, va2);
+        rc = vsnprintf(psz, cb, fmt, va2);
         va_end(va2);
 #else
         va2 = va;
-        rc = snprintf(psz, cb, fmt, va2);
+        rc = vsnprintf(psz, cb, fmt, va2);
 #endif
         if (rc < 0 || (size_t)rc < cb)
             break;
diff --git a/src/kmk/main.c b/src/kmk/main.c
index 2b45d9d..b648f42 100644
--- a/src/kmk/main.c
+++ b/src/kmk/main.c
@@ -1375,9 +1375,9 @@ main (int argc, char **argv, char **envp)
   char *unix_path = NULL;
   char *windows32_path = NULL;
 
-#ifndef ELECTRIC_HEAP /* Drop this because it prevents JIT debugging. */
+# ifndef ELECTRIC_HEAP /* Drop this because it prevents JIT debugging. */
   SetUnhandledExceptionFilter(handle_runtime_exceptions);
-#endif /* !ELECTRIC_HEAP */
+# endif /* !ELECTRIC_HEAP */
 
   /* start off assuming we have no shell */
   unixy_shell = 0;
diff --git a/src/kmk/misc.c b/src/kmk/misc.c
index a70a222..a22759b 100644
--- a/src/kmk/misc.c
+++ b/src/kmk/misc.c
@@ -291,6 +291,30 @@ message (prefix, fmt, va_alist)
 
   if (fmt != 0)
     {
+#ifdef KBUILD_OS_WINDOWS
+      char szMsg[16384];
+      int cchMsg = 0;
+      int cchUser;
+      if (prefix)
+        {
+          if (makelevel == 0)
+            cchMsg = snprintf (szMsg, sizeof(szMsg), "%s: ", program);
+          else
+            cchMsg = snprintf (szMsg, sizeof(szMsg), "%s[%u]: ", program, makelevel);
+        }
+      VA_START (args, fmt);
+      cchMsg += cchUser = vsnprintf (&szMsg[cchMsg], sizeof(szMsg) - cchMsg, fmt, args);
+      VA_END (args);
+      if (   cchMsg < sizeof(szMsg)
+          && cchUser >= 0)
+        {
+          extern size_t maybe_con_fwrite(void const *, size_t, size_t, FILE *);
+          szMsg[cchMsg++] = '\n';
+          maybe_con_fwrite(szMsg, cchMsg, 1, stdout);
+        }
+      else
+        {
+#endif
       if (prefix)
 	{
 	  if (makelevel == 0)
@@ -302,6 +326,9 @@ message (prefix, fmt, va_alist)
       VA_PRINTF (stdout, fmt, args);
       VA_END (args);
       putchar ('\n');
+#ifdef KBUILD_OS_WINDOWS
+        }
+#endif
     }
 
   fflush (stdout);
@@ -322,9 +349,36 @@ error (flocp, fmt, va_alist)
 #if USE_VARIADIC
   va_list args;
 #endif
+#ifdef KMK
+  char szMsg[16384];
+  int cchMsg = 0;
+  int cchUser;
+#endif
 
   log_working_directory (1);
 
+#ifdef KMK /* Try avoid getting the error split by child output.  */
+  if (flocp && flocp->filenm)
+    cchMsg = snprintf (szMsg, sizeof(szMsg), "%s:%lu: ", flocp->filenm, flocp->lineno);
+  else if (makelevel == 0)
+    cchMsg = snprintf (szMsg, sizeof(szMsg), "%s: ", program);
+  else
+    cchMsg = snprintf (szMsg, sizeof(szMsg), "%s[%u]: ", program, makelevel);
+
+  VA_START (args, fmt);
+  cchMsg += cchUser = vsnprintf (&szMsg[cchMsg], sizeof(szMsg) - cchMsg, fmt, args);
+  VA_END (args);
+  if (   cchMsg < sizeof(szMsg)
+      && cchUser >= 0)
+    {
+      extern size_t maybe_con_fwrite(void const *, size_t, size_t, FILE *);
+      szMsg[cchMsg++] = '\n';
+      maybe_con_fwrite(szMsg, cchMsg, 1, stderr);
+    }
+  else
+    {
+#endif /* KMK */
+
   if (flocp && flocp->filenm)
     fprintf (stderr, "%s:%lu: ", flocp->filenm, flocp->lineno);
   else if (makelevel == 0)
@@ -337,6 +391,9 @@ error (flocp, fmt, va_alist)
   VA_END (args);
 
   putc ('\n', stderr);
+#ifdef KMK
+    }
+#endif
   fflush (stderr);
 }
 
@@ -355,9 +412,38 @@ fatal (flocp, fmt, va_alist)
 #if USE_VARIADIC
   va_list args;
 #endif
+#ifdef KMK
+  char szMsg[16384];
+  int cchMsg = 0;
+  int cchUser;
+  const char *pszStop = _(".  Stop.\n");
+  int         cchStop = (int)strlen(pszStop);
+#endif
 
   log_working_directory (1);
 
+#ifdef KMK /* Try avoid getting the error split by child output.  */
+  if (flocp && flocp->filenm)
+    cchMsg = snprintf (szMsg, sizeof(szMsg), "%s:%lu: *** ", flocp->filenm, flocp->lineno);
+  else if (makelevel == 0)
+    cchMsg = snprintf (szMsg, sizeof(szMsg), "%s: *** ", program);
+  else
+    cchMsg = snprintf (szMsg, sizeof(szMsg), "%s[%u]: *** ", program, makelevel);
+
+  VA_START (args, fmt);
+  cchMsg += cchUser = vsnprintf (&szMsg[cchMsg], sizeof(szMsg) - cchMsg, fmt, args);
+  VA_END (args);
+  if (   cchMsg + cchStop <= sizeof(szMsg)
+      && cchUser >= 0)
+    {
+      extern size_t maybe_con_fwrite(void const *, size_t, size_t, FILE *);
+      memcpy(&szMsg[cchMsg], pszStop, cchStop);
+      cchMsg += cchStop;
+      maybe_con_fwrite(szMsg, cchMsg, 1, stderr);
+    }
+  else
+    {
+#endif /* KMK */
   if (flocp && flocp->filenm)
     fprintf (stderr, "%s:%lu: *** ", flocp->filenm, flocp->lineno);
   else if (makelevel == 0)
@@ -370,6 +456,9 @@ fatal (flocp, fmt, va_alist)
   VA_END (args);
 
   fputs (_(".  Stop.\n"), stderr);
+#ifdef KMK
+    }
+#endif
 
   die (2);
 }
diff --git a/src/lib/Makefile.kmk b/src/lib/Makefile.kmk
index f4bac14..b5833c2 100644
--- a/src/lib/Makefile.kmk
+++ b/src/lib/Makefile.kmk
@@ -1,4 +1,4 @@
-# $Id: Makefile.kmk 2886 2016-09-06 14:31:46Z bird $
+# $Id: Makefile.kmk 2906 2016-09-09 22:15:57Z bird $
 ## @file
 # Sub-makefile for various libraries and stuff.
 #
@@ -38,8 +38,11 @@ kUtil_DEFS.win = __WIN__
 kUtil_SOURCES = \
 	crc32.c \
 	md5.c \
+	maybe_con_write.c \
+	maybe_con_fwrite.c \
 	kbuild_version.c
 kUtil_SOURCES.win = \
+	msc_buffered_printf.c \
 	nt_fullpath.c \
 	nt_fullpath_cached.c \
 	quote_argv.c \
diff --git a/src/lib/maybe_con_fwrite.c b/src/lib/maybe_con_fwrite.c
new file mode 100644
index 0000000..6448434
--- /dev/null
+++ b/src/lib/maybe_con_fwrite.c
@@ -0,0 +1,114 @@
+/* $Id: maybe_con_fwrite.c 2906 2016-09-09 22:15:57Z bird $ */
+/** @file
+ * maybe_con_write - Optimized console output on windows.
+ */
+
+/*
+ * Copyright (c) 2016 knut st. osmundsen <bird-kBuild-spamx at anduin.net>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Alternatively, the content of this file may be used under the terms of the
+ * GPL version 2 or later, or LGPL version 2.1 or later.
+ */
+
+
+/*********************************************************************************************************************************
+*   Header Files                                                                                                                 *
+*********************************************************************************************************************************/
+#ifdef KBUILD_OS_WINDOWS
+# include <windows.h>
+#endif
+#include <errno.h>
+#include <stdio.h>
+#ifdef _MSC_VER
+# include <io.h>
+# include <conio.h>
+#endif
+
+
+
+/**
+ * Drop-in fwrite replacement for optimizing console output on windows.
+ *
+ *
+ * @returns Units written; 0 & errno on failure.
+ * @param   pvBuf               What to write.
+ * @param   cbUnit              How much to write in each unit.
+ * @param   cUnits              How many units to write.
+ * @param   pFile               The file to write to.
+ */
+size_t maybe_con_fwrite(void const *pvBuf, size_t cbUnit, size_t cUnits, FILE *pFile)
+{
+#ifdef KBUILD_OS_WINDOWS
+    /*
+     * If it's a TTY, do our own conversion to wide char and
+     * call WriteConsoleW directly.
+     */
+    if (   cbUnit > 0
+        && cUnits > 0
+        && (pFile == stdout || pFile == stderr))
+    {
+        int fd = fileno(pFile);
+        if (fd >= 0)
+        {
+            if (isatty(fd))
+            {
+                HANDLE hCon = (HANDLE)_get_osfhandle(fd);
+                if (   hCon != INVALID_HANDLE_VALUE
+                    && hCon != NULL)
+                {
+                    size_t   cbToWrite = cbUnit * cUnits;
+                    size_t   cwcTmp    = cbToWrite * 2 + 16;
+                    wchar_t *pawcTmp   = (wchar_t *)malloc(cwcTmp * sizeof(wchar_t));
+                    if (pawcTmp)
+                    {
+                        int           cwcToWrite;
+                        static UINT s_uConsoleCp = 0;
+                        if (s_uConsoleCp == 0)
+                            s_uConsoleCp = GetConsoleCP();
+
+                        cwcToWrite = MultiByteToWideChar(s_uConsoleCp, 0 /*dwFlags*/, pvBuf, (int)cbToWrite, pawcTmp, (int)(cwcTmp - 1));
+                        if (cwcToWrite > 0)
+                        {
+                            int rc;
+                            pawcTmp[cwcToWrite] = '\0';
+
+                            /* Let the CRT do the rest.  At least the Visual C++ 2010 CRT
+                               sources indicates _cputws will do the right thing we want.  */
+                            fflush(pFile);
+                            rc = _cputws(pawcTmp);
+                            free(pawcTmp);
+                            if (rc >= 0)
+                                return cUnits;
+                            return 0;
+                        }
+                        free(pawcTmp);
+                    }
+                }
+            }
+        }
+    }
+#endif
+
+    /*
+     * Semi regular write handling.
+     */
+    return fwrite(pvBuf, cbUnit, cUnits, pFile);
+}
diff --git a/src/lib/maybe_con_write.c b/src/lib/maybe_con_write.c
new file mode 100644
index 0000000..0b28a42
--- /dev/null
+++ b/src/lib/maybe_con_write.c
@@ -0,0 +1,116 @@
+/* $Id: maybe_con_write.c 2900 2016-09-09 14:42:06Z bird $ */
+/** @file
+ * maybe_con_write - Optimized console output on windows.
+ */
+
+/*
+ * Copyright (c) 2016 knut st. osmundsen <bird-kBuild-spamx at anduin.net>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Alternatively, the content of this file may be used under the terms of the
+ * GPL version 2 or later, or LGPL version 2.1 or later.
+ */
+
+
+/*********************************************************************************************************************************
+*   Header Files                                                                                                                 *
+*********************************************************************************************************************************/
+#ifdef KBUILD_OS_WINDOWS
+# include <windows.h>
+#endif
+#include <errno.h>
+#ifdef _MSC_VER
+# include <io.h>
+# include <conio.h>
+typedef intptr_t ssize_t;
+typedef unsigned int to_write_t;
+#else
+# include <unistd.h>
+typedef size_t to_write_t;
+#endif
+
+
+/**
+ * Drop-in write replacement for optimizing console output on windows.
+ *
+ * @returns Number of bytes written, -1 + errno on failure.
+ * @param   fd                  The file descript to write to.
+ * @param   pvBuf               What to write.
+ * @param   cbToWrite           How much to write.
+ */
+ssize_t maybe_con_write(int fd, void *pvBuf, size_t cbToWrite)
+{
+    ssize_t cbWritten;
+#ifdef KBUILD_OS_WINDOWS
+    /*
+     * If it's a TTY, do our own conversion to wide char and
+     * call WriteConsoleW directly.
+     */
+    if (cbToWrite > 0 && isatty(fd))
+    {
+        HANDLE hCon = (HANDLE)_get_osfhandle(fd);
+        if (   hCon != INVALID_HANDLE_VALUE
+            && hCon != NULL)
+        {
+            size_t   cwcTmp  = cbToWrite * 2 + 16;
+            wchar_t *pawcTmp = (wchar_t *)malloc(cwcTmp * sizeof(wchar_t));
+            if (pawcTmp)
+            {
+                int           cwcToWrite;
+                static UINT s_uConsoleCp = 0;
+                if (s_uConsoleCp == 0)
+                    s_uConsoleCp = GetConsoleCP();
+
+                cwcToWrite = MultiByteToWideChar(s_uConsoleCp, 0 /*dwFlags*/, pvBuf, (int)cbToWrite, pawcTmp, (int)(cwcTmp - 1));
+                if (cwcToWrite > 0)
+                {
+                    /* Let the CRT do the rest.  At least the Visual C++ 2010 CRT
+                       sources indicates _cputws will do the right thing we want.  */
+                    pawcTmp[cwcToWrite] = '\0';
+                    if (_cputws(pawcTmp) >= 0)
+                        return cbToWrite;
+                    return -1;
+                }
+            }
+        }
+    }
+#endif
+
+    /*
+     * Semi regular write handling.
+     */
+    cbWritten = write(fd, pvBuf, (to_write_t)cbToWrite);
+    if (cbWritten == cbToWrite)
+    { /* likely */ }
+    else if (cbWritten >= 0 || errno == EINTR)
+    {
+        if (cbWritten < 0)
+            cbWritten = 0;
+        while (cbWritten < (ssize_t)cbToWrite)
+        {
+            ssize_t cbThis = write(fd, (char *)pvBuf + cbWritten, (to_write_t)(cbToWrite - cbWritten));
+            if (cbThis >= 0)
+                cbWritten += cbThis;
+            else if (errno != EINTR)
+                return -1;
+        }
+    }
+    return cbWritten;
+}
diff --git a/src/lib/msc_buffered_printf.c b/src/lib/msc_buffered_printf.c
new file mode 100644
index 0000000..2638b4f
--- /dev/null
+++ b/src/lib/msc_buffered_printf.c
@@ -0,0 +1,254 @@
+/* $Id: msc_buffered_printf.c 2910 2016-09-10 00:57:29Z bird $ */
+/** @file
+ * printf, vprintf, fprintf, puts, fputs console optimizations for Windows/MSC.
+ */
+
+/*
+ * Copyright (c) 2016 knut st. osmundsen <bird-kBuild-spamx at anduin.net>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Alternatively, the content of this file may be used under the terms of the
+ * GPL version 2 or later, or LGPL version 2.1 or later.
+ */
+
+
+/*********************************************************************************************************************************
+*   Header Files                                                                                                                 *
+*********************************************************************************************************************************/
+#include <Windows.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <io.h>
+#include <conio.h>
+#include <malloc.h>
+
+#undef printf
+#undef vprintf
+#undef fprintf
+#undef puts
+#undef fputs
+#pragma warning(disable: 4273) /* inconsistent dll linkage*/
+
+extern size_t maybe_con_fwrite(void const *pvBuf, size_t cbUnit, size_t cUnits, FILE *pFile);
+
+
+/**
+ * Replaces printf for MSC to speed up console output.
+ *
+ * @returns chars written on success, -1 and errno on failure.
+ * @param   pszFormat           The format string.
+ * @param   ...                 Format arguments.
+ */
+__declspec(dllexport)
+int __cdecl printf(const char *pszFormat, ...)
+{
+    int cchRet;
+    va_list va;
+    va_start(va, pszFormat);
+    cchRet = vprintf(pszFormat, va);
+    va_end(va);
+    return cchRet;
+}
+
+
+/**
+ * Replaces vprintf for MSC to speed up console output.
+ *
+ * @returns chars written on success, -1 and errno on failure.
+ * @param   pszFormat           The format string.
+ * @param   va                  Format arguments.
+ */
+__declspec(dllexport)
+int __cdecl vprintf(const char *pszFormat, va_list va)
+{
+    /*
+     * If it's a TTY, try format into a stack buffer and output using our
+     * console optimized fwrite wrapper.
+     */
+    if (*pszFormat != '\0')
+    {
+        int fd = fileno(stdout);
+        if (fd >= 0)
+        {
+            if (isatty(fd))
+            {
+                char *pszTmp = (char *)alloca(16384);
+                va_list va2 = va;
+                int cchRet = vsnprintf(pszTmp, 16384, pszFormat, va2);
+                if (cchRet < 16384 - 1)
+                    return (int)maybe_con_fwrite(pszTmp, cchRet, 1, stdout);
+            }
+        }
+    }
+
+    /*
+     * Fallback.
+     */
+    return vfprintf(stdout, pszFormat, va);
+}
+
+
+/**
+ * Replaces fprintf for MSC to speed up console output.
+ *
+ * @returns chars written on success, -1 and errno on failure.
+ * @param   pFile               The output file/stream.
+ * @param   pszFormat           The format string.
+ * @param   va                  Format arguments.
+ */
+__declspec(dllexport)
+int __cdecl fprintf(FILE *pFile, const char *pszFormat, ...)
+{
+    va_list va;
+    int cchRet;
+
+    /*
+     * If it's a TTY, try format into a stack buffer and output using our
+     * console optimized fwrite wrapper.
+     */
+    if (*pszFormat != '\0')
+    {
+        int fd = fileno(pFile);
+        if (fd >= 0)
+        {
+            if (isatty(fd))
+            {
+                char *pszTmp = (char *)alloca(16384);
+                if (pszTmp)
+                {
+                    va_start(va, pszFormat);
+                    cchRet = vsnprintf(pszTmp, 16384, pszFormat, va);
+                    va_end(va);
+                    if (cchRet < 16384 - 1)
+                        return (int)maybe_con_fwrite(pszTmp, cchRet, 1, pFile);
+                }
+            }
+        }
+    }
+
+    /*
+     * Fallback.
+     */
+    va_start(va, pszFormat);
+    cchRet = vfprintf(pFile, pszFormat, va);
+    va_end(va);
+    return cchRet;
+}
+
+
+/**
+ * Replaces puts for MSC to speed up console output.
+ *
+ * @returns Units written; 0 & errno on failure.
+ * @param   pszString           The string to write. (newline is appended)
+ */
+__declspec(dllexport)
+int __cdecl puts(const char *pszString)
+{
+    size_t cchString = strlen(pszString);
+    size_t cch;
+
+    /*
+     * If it's a TTY, we convert it to a wide char string with a newline
+     * appended right here.  Going thru maybe_con_fwrite is just extra
+     * buffering due to the added newline.
+     */
+    if (*pszString != '\0')
+    {
+        int fd = fileno(stdout);
+        if (fd >= 0)
+        {
+            if (isatty(fd))
+            {
+                HANDLE hCon = (HANDLE)_get_osfhandle(fd);
+                if (   hCon != INVALID_HANDLE_VALUE
+                    && hCon != NULL)
+                {
+                    /* We need to append a newline, so we can just as well do the conversion here. */
+                    size_t   cwcTmp  = cchString * 2 + 16 + 2;
+                    wchar_t *pawcTmp = (wchar_t *)malloc(cwcTmp * sizeof(wchar_t));
+                    if (pawcTmp)
+                    {
+                        int           cwcToWrite;
+                        static UINT s_uConsoleCp = 0;
+                        if (s_uConsoleCp == 0)
+                            s_uConsoleCp = GetConsoleCP();
+
+                        cwcToWrite = MultiByteToWideChar(s_uConsoleCp, 0 /*dwFlags*/, pszString, (int)cchString, pawcTmp,
+                                                         (int)(cwcTmp - 2));
+                        if (cwcToWrite > 0)
+                        {
+                            int rc;
+
+                            pawcTmp[cwcToWrite++] = '\n';
+                            pawcTmp[cwcToWrite]   = '\0';
+
+                            /* Let the CRT do the rest.  At least the Visual C++ 2010 CRT
+                               sources indicates _cputws will do the right thing we want.  */
+                            fflush(stdout);
+                            rc = _cputws(pawcTmp);
+                            free(pawcTmp);
+                            return rc;
+                        }
+                        free(pawcTmp);
+                    }
+                }
+            }
+        }
+    }
+
+    /*
+     * Fallback.
+     */
+    cch = fwrite(pszString, cchString, 1, stdout);
+    if (cch == cchString)
+    {
+        if (putc('\n', stdout) != EOF)
+            return 0;
+    }
+    return -1;
+}
+
+
+/**
+ * Replaces puts for MSC to speed up console output.
+ *
+ * @returns Units written; 0 & errno on failure.
+ * @param   pszString           The string to write (no newline added).
+ * @param   pFile               The output file.
+ */
+__declspec(dllexport)
+int __cdecl fputs(const char *pszString, FILE *pFile)
+{
+    size_t cchString = strlen(pszString);
+    size_t cch = maybe_con_fwrite(pszString, cchString, 1, pFile);
+    if (cch == cchString)
+        return 0;
+    return -1;
+}
+
+
+
+void * const __imp_printf  = (void *)(uintptr_t)printf;
+void * const __imp_vprintf = (void *)(uintptr_t)vprintf;
+void * const __imp_fprintf = (void *)(uintptr_t)fprintf;
+void * const __imp_puts    = (void *)(uintptr_t)puts;
+void * const __imp_fputs   = (void *)(uintptr_t)fputs;
+
diff --git a/src/lib/nt/ntstuff.h b/src/lib/nt/ntstuff.h
index a784ebc..f9ed594 100644
--- a/src/lib/nt/ntstuff.h
+++ b/src/lib/nt/ntstuff.h
@@ -1,4 +1,4 @@
-/* $Id: ntstuff.h 2862 2016-09-02 02:39:56Z bird $ */
+/* $Id: ntstuff.h 2900 2016-09-09 14:42:06Z bird $ */
 /** @file
  * Definitions, types, prototypes and globals for NT.
  */
@@ -74,6 +74,59 @@ typedef struct MY_STRING
 } MY_STRING;
 typedef MY_STRING MY_ANSI_STRING;
 
+typedef struct MY_CURDIR
+{
+    UNICODE_STRING      DosPath;
+    HANDLE              Handle;
+} MY_CURDIR;
+typedef MY_CURDIR *PMY_CURDIR;
+
+typedef struct MY_RTL_DRIVE_LETTER_CURDIR
+{
+    USHORT              Flags;
+    USHORT              Length;
+    ULONG               TimeStamp;
+    MY_ANSI_STRING      DosPath;
+} MY_RTL_DRIVE_LETTER_CURDIR;
+typedef MY_RTL_DRIVE_LETTER_CURDIR *PRTL_DRIVE_LETTER_CURDIR;
+
+typedef struct MY_RTL_USER_PROCESS_PARAMETERS
+{
+    ULONG               MaximumLength;
+    ULONG               Length;
+    ULONG               Flags;
+    ULONG               DebugFlags;
+    HANDLE              ConsoleHandle;
+    ULONG               ConsoleFlags;
+    HANDLE              StandardInput;
+    HANDLE              StandardOutput;
+    HANDLE              StandardError;
+    MY_CURDIR           CurrentDirectory;
+    MY_UNICODE_STRING   DllPath;
+    MY_UNICODE_STRING   ImagePathName;
+    MY_UNICODE_STRING   CommandLine;
+    PWSTR               Environment;
+    ULONG               StartingX;
+    ULONG               StartingY;
+    ULONG               CountX;
+    ULONG               CountY;
+    ULONG               CountCharsX;
+    ULONG               CountCharsY;
+    ULONG               FillAttribute;
+    ULONG               WindowFlags;
+    ULONG               ShowWindowFlags;
+    MY_UNICODE_STRING   WindowTitle;
+    MY_UNICODE_STRING   DesktopInfo;
+    MY_UNICODE_STRING   ShellInfo;
+    MY_UNICODE_STRING   RuntimeInfo;
+    MY_RTL_DRIVE_LETTER_CURDIR CurrentDirectories[0x20];
+    SIZE_T              EnvironmentSize;        /* >= Vista+ */
+    SIZE_T              EnvironmentVersion;     /* >= Windows 7. */
+    PVOID               PackageDependencyData;  /* >= Windows 8 or Windows 8.1. */
+    ULONG               ProcessGroupId;         /* >= Windows 8 or Windows 8.1. */
+} MY_RTL_USER_PROCESS_PARAMETERS;
+typedef MY_RTL_USER_PROCESS_PARAMETERS *PMY_RTL_USER_PROCESS_PARAMETERS;
+
 typedef struct MY_OBJECT_ATTRIBUTES
 {
     ULONG               Length;
diff --git a/src/sed/Makefile.kmk b/src/sed/Makefile.kmk
index 7a6bc2f..1fec22c 100644
--- a/src/sed/Makefile.kmk
+++ b/src/sed/Makefile.kmk
@@ -1,4 +1,4 @@
-# $Id: Makefile.kmk 2829 2016-08-15 10:52:09Z bird $
+# $Id: Makefile.kmk 2909 2016-09-09 22:54:17Z bird $
 ## @file
 # Sub-Makefile for kmk_sed.
 #
@@ -88,6 +88,8 @@ kmk_sed_SOURCES.win = \
 	lib/getline.c \
 	../lib/startuphacks-win.c
 
+kmk_sed_LIBS.win = $(LIB_KUTIL) # for stdout optimizations.
+
 include $(FILE_KBUILD_SUB_FOOTER)
 
 #
diff --git a/src/sed/lib/utils.c b/src/sed/lib/utils.c
index 647fd6d..0fe8671 100644
--- a/src/sed/lib/utils.c
+++ b/src/sed/lib/utils.c
@@ -37,6 +37,11 @@
 
 #include "utils.h"
 
+#ifdef KBUILD_OS_WINDOWS /* bird: Way faster console output! */
+extern size_t maybe_con_fwrite(void const *, size_t, size_t, FILE *);
+# define fwrite maybe_con_fwrite
+#endif
+
 const char *myname;
 
 /* Store information about files opened with ck_fopen

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-virtualbox/kbuild.git



More information about the Pkg-virtualbox-commits mailing list