Index: /trunk/src/kWorker/kWorker.c
===================================================================
--- /trunk/src/kWorker/kWorker.c	(revision 2915)
+++ /trunk/src/kWorker/kWorker.c	(revision 2916)
@@ -32,4 +32,7 @@
 *********************************************************************************************************************************/
 //#undef NDEBUG
+//#define K_STRICT 1
+//#define KW_LOG_ENABLED
+
 #define PSAPI_VERSION 1
 #include <k/kHlp.h>
@@ -75,12 +78,22 @@
 #define WITH_CONSOLE_OUTPUT_BUFFERING
 
-
-/** String constant comma length.   */
-#define TUPLE(a_sz)                     a_sz, sizeof(a_sz) - 1
+/** @def WITH_STD_OUT_ERR_BUFFERING
+ * Enables buffering of standard output and standard error buffer as well as
+ * removal of annoying source file echo by cl.exe. */
+#define WITH_STD_OUT_ERR_BUFFERING
+
+/** @def WITH_LOG_FILE
+ * Log to file instead of stderr. */
+#define WITH_LOG_FILE
+
+#ifndef NDEBUG
+# define KW_LOG_ENABLED
+#endif
+
 
 /** @def KW_LOG
  * Generic logging.
  * @param a     Argument list for kwDbgPrintf  */
-#ifndef NDEBUG
+#ifdef KW_LOG_ENABLED
 # define KW_LOG(a) kwDbgPrintf a
 #else
@@ -91,5 +104,5 @@
  * FS cache logging.
  * @param a     Argument list for kwDbgPrintf  */
-#ifndef NDEBUG
+#ifdef KW_LOG_ENABLED
 # define KWFS_LOG(a) kwDbgPrintf a
 #else
@@ -97,8 +110,17 @@
 #endif
 
+/** @def KWOUT_LOG
+ * Output related logging.
+ * @param a     Argument list for kwDbgPrintf  */
+#ifdef KW_LOG_ENABLED
+# define KWOUT_LOG(a) kwDbgPrintf a
+#else
+# define KWOUT_LOG(a) do { } while (0)
+#endif
+
 /** @def KWCRYPT_LOG
  * FS cache logging.
  * @param a     Argument list for kwDbgPrintf  */
-#ifndef NDEBUG
+#ifdef KW_LOG_ENABLED
 # define KWCRYPT_LOG(a) kwDbgPrintf a
 #else
@@ -123,7 +145,7 @@
 /** Marks unfinished code.  */
 #if 1
-# define KWFS_TODO()    do { kwErrPrintf("\nHit TODO on line %u in %s!\n", __LINE__, __FUNCTION__); __debugbreak(); } while (0)
+# define KWFS_TODO()    do { kwErrPrintf("\nHit TODO on line %u in %s!\n", __LINE__, __FUNCTION__); fflush(stderr); __debugbreak(); } while (0)
 #else
-# define KWFS_TODO()    do { kwErrPrintf("\nHit TODO on line %u in %s!\n", __LINE__, __FUNCTION__); } while (0)
+# define KWFS_TODO()    do { kwErrPrintf("\nHit TODO on line %u in %s!\n", __LINE__, __FUNCTION__); fflush(stderr); } while (0)
 #endif
 
@@ -132,4 +154,7 @@
 /** User data key for a cached file. */
 #define KW_DATA_KEY_CACHED_FILE         (~(KUPTR)65521)
+
+/** String constant comma length.   */
+#define TUPLE(a_sz)                     a_sz, sizeof(a_sz) - 1
 
 
@@ -356,5 +381,5 @@
  * Console line buffer or output full buffer.
  */
-typedef struct KWCONSOLEOUTPUTLINE
+typedef struct KWOUTPUTSTREAMBUF
 {
     /** The main output handle. */
@@ -366,5 +391,7 @@
      * boundraries when ever possible. */
     KBOOL               fIsConsole;
-    KU8                 abPadding[3];
+    /** Compressed GetFileType result. */
+    KU8                 fFileType;
+    KU8                 abPadding[2];
     union
     {
@@ -384,13 +411,15 @@
             /** Amount of pending output (in chars). */
             KU32                cchBuf;
+#ifdef WITH_STD_OUT_ERR_BUFFERING
             /** The allocated buffer size (in chars).   */
             KU32                cchBufAlloc;
             /** Pending output. */
             char               *pchBuf;
+#endif
         } Fully;
     } u;
-} KWCONSOLEOUTPUTLINE;
+} KWOUTPUTSTREAMBUF;
 /** Pointer to a console line buffer. */
-typedef KWCONSOLEOUTPUTLINE *PKWCONSOLEOUTPUTLINE;
+typedef KWOUTPUTSTREAMBUF *PKWOUTPUTSTREAMBUF;
 
 /**
@@ -423,6 +452,6 @@
     KWHANDLETYPE_FSOBJ_READ_CACHE,
     KWHANDLETYPE_TEMP_FILE,
-    KWHANDLETYPE_TEMP_FILE_MAPPING
-    //KWHANDLETYPE_CONSOLE_CACHE
+    KWHANDLETYPE_TEMP_FILE_MAPPING,
+    KWHANDLETYPE_OUTPUT_BUF
 } KWHANDLETYPE;
 
@@ -431,4 +460,6 @@
 {
     KWHANDLETYPE        enmType;
+    /** Number of references   */
+    KU32                cRefs;
     /** The current file offset. */
     KU32                offFile;
@@ -445,4 +476,8 @@
         /** Temporary file handle or mapping handle. */
         PKWFSTEMPFILE       pTempFile;
+#ifdef WITH_CONSOLE_OUTPUT_BUFFERING
+        /** Buffered output stream. */
+        PKWOUTPUTSTREAMBUF  pOutBuf;
+#endif
     } u;
 } KWHANDLE;
@@ -618,4 +653,8 @@
     /** Number of active handles in the table. */
     KU32            cActiveHandles;
+    /** Number of handles in the handle table that will not be freed.   */
+    KU32            cFixedHandles;
+    /** Total number of leaked handles. */
+    KU32            cLeakedHandles;
 
     /** Head of the list of temporary file. */
@@ -636,5 +675,5 @@
     PKWEXITCALLACK  pExitCallbackHead;
 
-    UNICODE_STRING  SavedCommandLine;
+    MY_UNICODE_STRING SavedCommandLine;
 
 #ifdef WITH_HASH_MD5_CACHE
@@ -661,8 +700,12 @@
 
 #ifdef WITH_CONSOLE_OUTPUT_BUFFERING
-    /** Standard output (and whatever else) line buffer. */
-    KWCONSOLEOUTPUTLINE StdOut;
-    /** Standard error line buffer. */
-    KWCONSOLEOUTPUTLINE StdErr;
+    /** The internal standard output handle. */
+    KWHANDLE            HandleStdOut;
+    /** The internal standard error handle. */
+    KWHANDLE            HandleStdErr;
+    /** Standard output (and whatever else) buffer. */
+    KWOUTPUTSTREAMBUF   StdOut;
+    /** Standard error buffer. */
+    KWOUTPUTSTREAMBUF   StdErr;
     /** Combined buffer of completed lines. */
     KWCONSOLEOUTPUT     Combined;
@@ -749,4 +792,8 @@
 static KU8          g_abDefLdBuf[16*1024*1024];
 
+#ifdef WITH_LOG_FILE
+/** Log file handle.   */
+static HANDLE g_hLogFile = INVALID_HANDLE_VALUE;
+#endif
 
 
@@ -756,7 +803,7 @@
 static FNKLDRMODGETIMPORT kwLdrModuleGetImportCallback;
 static int kwLdrModuleResolveAndLookup(const char *pszName, PKWMODULE pExe, PKWMODULE pImporter, PKWMODULE *ppMod);
-static KBOOL kwSandboxHandleTableEnter(PKWSANDBOX pSandbox, PKWHANDLE pHandle);
+static KBOOL kwSandboxHandleTableEnter(PKWSANDBOX pSandbox, PKWHANDLE pHandle, HANDLE hHandle);
 #ifdef WITH_CONSOLE_OUTPUT_BUFFERING
-static void kwSandboxConsoleWriteA(PKWSANDBOX pSandbox, PKWCONSOLEOUTPUTLINE pLineBuf, const char *pchBuffer, KU32 cchToWrite);
+static void kwSandboxConsoleWriteA(PKWSANDBOX pSandbox, PKWOUTPUTSTREAMBUF pLineBuf, const char *pchBuffer, KU32 cchToWrite);
 #endif
 
@@ -773,7 +820,30 @@
     {
         DWORD const dwSavedErr = GetLastError();
-
+#ifdef WITH_LOG_FILE
+        DWORD       dwIgnored;
+        char        szTmp[2048];
+        int         cchPrefix = _snprintf(szTmp, sizeof(szTmp), "%x:%x: ", GetCurrentProcessId(), GetCurrentThreadId());
+        int         cch = vsnprintf(&szTmp[cchPrefix], sizeof(szTmp) - cchPrefix, pszFormat, va);
+        if (cch < (int)sizeof(szTmp) - 1 - cchPrefix)
+            cch += cchPrefix;
+        else
+        {
+            cch = sizeof(szTmp) - 1;
+            szTmp[cch] = '\0';
+        }
+
+        if (g_hLogFile == INVALID_HANDLE_VALUE)
+        {
+            wchar_t wszFilename[128];
+            _snwprintf(wszFilename, K_ELEMENTS(wszFilename), L"kWorker-%x-%x.log", GetTickCount(), GetCurrentProcessId());
+            g_hLogFile = CreateFileW(wszFilename, GENERIC_WRITE, FILE_SHARE_READ, NULL /*pSecAttrs*/, CREATE_ALWAYS,
+                                     FILE_ATTRIBUTE_NORMAL, NULL /*hTemplateFile*/);
+        }
+
+        WriteFile(g_hLogFile, szTmp, cch, &dwIgnored, NULL /*pOverlapped*/);
+#else
         fprintf(stderr, "debug: ");
         vfprintf(stderr, pszFormat, va);
+#endif
 
         SetLastError(dwSavedErr);
@@ -4265,9 +4335,10 @@
         {
             pHandle->enmType            = !fMapping ? KWHANDLETYPE_TEMP_FILE : KWHANDLETYPE_TEMP_FILE_MAPPING;
+            pHandle->cRefs              = 1;
             pHandle->offFile            = 0;
             pHandle->hHandle            = hFile;
             pHandle->dwDesiredAccess    = dwDesiredAccess;
             pHandle->u.pTempFile        = pTempFile;
-            if (kwSandboxHandleTableEnter(&g_Sandbox, pHandle))
+            if (kwSandboxHandleTableEnter(&g_Sandbox, pHandle, hFile))
             {
                 pTempFile->cActiveHandles++;
@@ -4685,9 +4756,10 @@
                 {
                     pHandle->enmType            = KWHANDLETYPE_FSOBJ_READ_CACHE;
+                    pHandle->cRefs              = 1;
                     pHandle->offFile            = 0;
                     pHandle->hHandle            = *phFile;
                     pHandle->dwDesiredAccess    = dwDesiredAccess;
                     pHandle->u.pCachedFile      = pCachedFile;
-                    if (kwSandboxHandleTableEnter(&g_Sandbox, pHandle))
+                    if (kwSandboxHandleTableEnter(&g_Sandbox, pHandle, pHandle->hHandle))
                         return K_TRUE;
 
@@ -4773,6 +4845,14 @@
     }
 
+    /*
+     * Okay, normal.
+     */
     hFile = CreateFileA(pszFilename, dwDesiredAccess, dwShareMode, pSecAttrs,
                         dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
+    if (hFile != INVALID_HANDLE_VALUE)
+    {
+        kHlpAssert(   KW_HANDLE_TO_INDEX(hFile) >= g_Sandbox.cHandles
+                   || g_Sandbox.papHandles[KW_HANDLE_TO_INDEX(hFile)] == NULL);
+    }
     KWFS_LOG(("CreateFileA(%s) -> %p\n", pszFilename, hFile));
     return hFile;
@@ -4834,6 +4914,15 @@
     else
         KWFS_LOG(("CreateFileW: incompatible disposition %u\n", dwCreationDisposition));
+
+    /*
+     * Okay, normal.
+     */
     hFile = CreateFileW(pwszFilename, dwDesiredAccess, dwShareMode, pSecAttrs,
                         dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
+    if (hFile != INVALID_HANDLE_VALUE)
+    {
+        kHlpAssert(   KW_HANDLE_TO_INDEX(hFile) >= g_Sandbox.cHandles
+                   || g_Sandbox.papHandles[KW_HANDLE_TO_INDEX(hFile)] == NULL);
+    }
     KWFS_LOG(("CreateFileW(%ls) -> %p\n", pwszFilename, hFile));
     return hFile;
@@ -4862,6 +4951,7 @@
                     cbFile = pHandle->u.pTempFile->cbFile;
                     break;
+#endif
                 case KWHANDLETYPE_TEMP_FILE_MAPPING:
-#endif
+                case KWHANDLETYPE_OUTPUT_BUF:
                 default:
                     kHlpAssertFailed();
@@ -4943,6 +5033,7 @@
                     cbFile = pHandle->u.pTempFile->cbFile;
                     break;
+#endif
                 case KWHANDLETYPE_TEMP_FILE_MAPPING:
-#endif
+                case KWHANDLETYPE_OUTPUT_BUF:
                 default:
                     kHlpAssertFailed();
@@ -5100,7 +5191,8 @@
                     return TRUE;
                 }
+#endif /* WITH_TEMP_MEMORY_FILES */
 
                 case KWHANDLETYPE_TEMP_FILE_MAPPING:
-#endif /* WITH_TEMP_MEMORY_FILES */
+                case KWHANDLETYPE_OUTPUT_BUF:
                 default:
                     kHlpAssertFailed();
@@ -5136,5 +5228,5 @@
 }
 
-#ifdef WITH_CONSOLE_OUTPUT_BUFFERING
+#ifdef WITH_STD_OUT_ERR_BUFFERING
 
 /**
@@ -5179,5 +5271,5 @@
  * @param   cchToWrite          How much to write.
  */
-static void kwSandboxOutBufWrite(PKWSANDBOX pSandbox, PKWCONSOLEOUTPUTLINE pOutBuf, const char *pchBuffer, KU32 cchToWrite)
+static void kwSandboxOutBufWrite(PKWSANDBOX pSandbox, PKWOUTPUTSTREAMBUF pOutBuf, const char *pchBuffer, KU32 cchToWrite)
 {
     if (pOutBuf->u.Fully.cchBufAlloc > 0)
@@ -5223,5 +5315,5 @@
         while (cchToWrite > 0)
         {
-            char const *pchNewLine = (char *)memchr(pchBuffer, '\n', cchToWrite);
+            char const *pchNewLine = (const char *)memchr(pchBuffer, '\n', cchToWrite);
             KU32        cchLine    = pchNewLine ? (KU32)(pchNewLine - pchBuffer) + 1 : cchToWrite;
             if (cchLine <= pOutBuf->u.Fully.cchBufAlloc - pOutBuf->u.Fully.cchBuf)
@@ -5240,4 +5332,5 @@
                      || pOutBuf->u.Fully.pchBuf[pOutBuf->u.Fully.cchBuf - 1] != '\n')
             {
+                KWOUT_LOG(("kwSandboxOutBufWrite: flushing %u bytes, writing %u bytes\n", pOutBuf->u.Fully.cchBuf, cchLine));
                 if (pOutBuf->u.Fully.cchBuf > 0)
                 {
@@ -5252,4 +5345,5 @@
             else
             {
+                KWOUT_LOG(("kwSandboxOutBufWrite: flushing %u bytes\n", pOutBuf->u.Fully.cchBuf));
                 kwSandboxOutBufWriteIt(pOutBuf->hBackup, pOutBuf->u.Fully.pchBuf, pOutBuf->u.Fully.cchBuf);
                 memcpy(&pOutBuf->u.Fully.pchBuf[0], pchBuffer, cchLine);
@@ -5263,8 +5357,8 @@
     }
 }
-#endif  /* WITH_CONSOLE_OUTPUT_BUFFERING */
+
+#endif  /* WITH_STD_OUT_ERR_BUFFERING */
 
 #ifdef WITH_TEMP_MEMORY_FILES
-
 static KBOOL kwFsTempFileEnsureSpace(PKWFSTEMPFILE pTempFile, KU32 offFile, KU32 cbNeeded)
 {
@@ -5321,6 +5415,8 @@
     return K_FALSE;
 }
-
-
+#endif /* WITH_TEMP_MEMORY_FILES */
+
+
+#if defined(WITH_TEMP_MEMORY_FILES) || defined(WITH_STD_OUT_ERR_BUFFERING)
 /** Kernel32 - WriteFile */
 static BOOL WINAPI kwSandbox_Kernel32_WriteFile(HANDLE hFile, LPCVOID pvBuffer, DWORD cbToWrite, LPDWORD pcbActuallyWritten,
@@ -5336,4 +5432,5 @@
             switch (pHandle->enmType)
             {
+# ifdef WITH_TEMP_MEMORY_FILES
                 case KWHANDLETYPE_TEMP_FILE:
                 {
@@ -5390,4 +5487,5 @@
                     return FALSE;
                 }
+# endif
 
                 case KWHANDLETYPE_FSOBJ_READ_CACHE:
@@ -5396,4 +5494,32 @@
                     *pcbActuallyWritten = 0;
                     return FALSE;
+
+# if defined(WITH_STD_OUT_ERR_BUFFERING) || defined(WITH_CONSOLE_OUTPUT_BUFFERING)
+                /*
+                 * Standard output & error.
+                 */
+                case KWHANDLETYPE_OUTPUT_BUF:
+                {
+                    PKWOUTPUTSTREAMBUF pOutBuf = pHandle->u.pOutBuf;
+                    if (pOutBuf->fIsConsole)
+                    {
+                        kwSandboxConsoleWriteA(&g_Sandbox, pOutBuf, (const char *)pvBuffer, cbToWrite);
+                        KWOUT_LOG(("WriteFile(%p [console]) -> TRUE\n", hFile));
+                    }
+                    else
+                    {
+#  ifdef WITH_STD_OUT_ERR_BUFFERING
+                        kwSandboxOutBufWrite(&g_Sandbox, pOutBuf, (const char *)pvBuffer, cbToWrite);
+                        KWOUT_LOG(("WriteFile(%p [std%s], 's*.*', %#x) -> TRUE\n", hFile,
+                                   pOutBuf == &g_Sandbox.StdErr ? "err" : "out", cbToWrite, cbToWrite, pvBuffer, cbToWrite));
+#  else
+                        kHlpAssertFailed();
+#  endif
+                    }
+                    if (pcbActuallyWritten)
+                        *pcbActuallyWritten = cbToWrite;
+                    return TRUE;
+                }
+# endif
 
                 default:
@@ -5407,25 +5533,5 @@
     }
 
-#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;
-        }
-        kwSandboxOutBufWrite(&g_Sandbox, pLineBuf, (const char *)pvBuffer, cbToWrite);
-        KWFS_LOG(("WriteFile(stdout/err) -> TRUE\n", hFile));
-        return TRUE;
-    }
-#endif
-
-    KWFS_LOG(("WriteFile(%p)\n", hFile));
+    KWFS_LOG(("WriteFile(%p,,%#x)\n", hFile, cbToWrite));
     return WriteFile(hFile, pvBuffer, cbToWrite, pcbActuallyWritten, pOverlapped);
 }
@@ -5451,4 +5557,7 @@
 }
 
+#endif /* WITH_TEMP_MEMORY_FILES || WITH_STD_OUT_ERR_BUFFERING */
+
+#ifdef WITH_TEMP_MEMORY_FILES
 
 /** Kernel32 - SetEndOfFile; */
@@ -5485,4 +5594,9 @@
                     return FALSE;
 
+                case KWHANDLETYPE_OUTPUT_BUF:
+                    kHlpAssertFailed();
+                    SetLastError(pHandle->u.pOutBuf->fIsConsole ? ERROR_INVALID_OPERATION : ERROR_ACCESS_DENIED);
+                    return FALSE;
+
                 default:
                 case KWHANDLETYPE_TEMP_FILE_MAPPING:
@@ -5518,4 +5632,22 @@
                     KWFS_LOG(("GetFileType(%p) -> FILE_TYPE_DISK [temp]\n", hFile));
                     return FILE_TYPE_DISK;
+
+                case KWHANDLETYPE_OUTPUT_BUF:
+                {
+                    PKWOUTPUTSTREAMBUF pOutBuf = pHandle->u.pOutBuf;
+                    DWORD fRet;
+                    if (pOutBuf->fFileType != KU8_MAX)
+                    {
+                        fRet = (pOutBuf->fFileType & 0xf) | ((pOutBuf->fFileType & (FILE_TYPE_REMOTE >> 8)) << 8);
+                        KWFS_LOG(("GetFileType(%p) -> %#x [outbuf]\n", hFile, fRet));
+                    }
+                    else
+                    {
+                        fRet = GetFileType(hFile);
+                        KWFS_LOG(("GetFileType(%p) -> %#x [outbuf, fallback]\n", hFile, fRet));
+                    }
+                    return fRet;
+                }
+
             }
         }
@@ -5550,4 +5682,8 @@
                     return pHandle->u.pTempFile->cbFile;
 
+                case KWHANDLETYPE_OUTPUT_BUF:
+                    /* do default */
+                    break;
+
                 default:
                     kHlpAssertFailed();
@@ -5584,4 +5720,8 @@
                     pcbFile->QuadPart = pHandle->u.pTempFile->cbFile;
                     return TRUE;
+
+                case KWHANDLETYPE_OUTPUT_BUF:
+                    /* do default */
+                    break;
 
                 default:
@@ -5654,6 +5794,7 @@
                 case KWHANDLETYPE_FSOBJ_READ_CACHE:
                 case KWHANDLETYPE_TEMP_FILE:
+                case KWHANDLETYPE_OUTPUT_BUF:
                     kHlpAssertFailed();
-                    SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+                    SetLastError(ERROR_INVALID_OPERATION);
                     return NULL;
 
@@ -5749,6 +5890,60 @@
 /** @todo UnmapViewOfFileEx */
 
-
 #endif /* WITH_TEMP_MEMORY_FILES */
+
+
+/** Kernel32 - DuplicateHandle */
+static BOOL WINAPI kwSandbox_Kernel32_DuplicateHandle(HANDLE hSrcProc, HANDLE hSrc, HANDLE hDstProc, PHANDLE phNew,
+                                                      DWORD dwDesiredAccess, BOOL fInheritHandle, DWORD dwOptions)
+{
+    BOOL fRet;
+
+    /*
+     * We must catch our handles being duplicated.
+     */
+    if (hSrcProc == GetCurrentProcess())
+    {
+        KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hSrc);
+        kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
+        if (idxHandle < g_Sandbox.cHandles)
+        {
+            PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle];
+            if (pHandle)
+            {
+                fRet = DuplicateHandle(hSrcProc, hSrc, hDstProc, phNew, dwDesiredAccess, fInheritHandle, dwOptions);
+                if (fRet)
+                {
+                    if (kwSandboxHandleTableEnter(&g_Sandbox, pHandle, *phNew))
+                    {
+                        pHandle->cRefs++;
+                        KWFS_LOG(("DuplicateHandle(%p, %p, %p, , %#x, %d, %#x) -> TRUE, %p [intercepted handle] enmType=%d cRef=%d\n",
+                                  hSrcProc, hSrc, hDstProc, dwDesiredAccess, fInheritHandle, dwOptions, *phNew,
+                                  pHandle->enmType, pHandle->cRefs));
+                    }
+                    else
+                    {
+                        fRet = FALSE;
+                        SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+                        KWFS_LOG(("DuplicateHandle(%p, %p, %p, , %#x, %d, %#x) -> !FALSE!, %p [intercepted handle] enmType=%d\n",
+                                  hSrcProc, hSrc, hDstProc, dwDesiredAccess, fInheritHandle, dwOptions, *phNew, pHandle->enmType));
+                    }
+                }
+                else
+                    KWFS_LOG(("DuplicateHandle(%p, %p, %p, , %#x, %d, %#x) -> FALSE [intercepted handle] enmType=%d\n",
+                              hSrcProc, hSrc, hDstProc, dwDesiredAccess, fInheritHandle, dwOptions, pHandle->enmType));
+                return fRet;
+            }
+        }
+    }
+
+    /*
+     * Not one of ours, just do what the caller asks and log it.
+     */
+    fRet = DuplicateHandle(hSrcProc, hSrc, hDstProc, phNew, dwDesiredAccess, fInheritHandle, dwOptions);
+    KWFS_LOG(("DuplicateHandle(%p, %p, %p, , %#x, %d, %#x) -> %d, %p\n", hSrcProc, hSrc, hDstProc, dwDesiredAccess,
+              fInheritHandle, dwOptions, fRet, *phNew));
+    return fRet;
+}
+
 
 /** Kernel32 - CloseHandle */
@@ -5758,31 +5953,50 @@
     KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hObject);
     kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
-    if (   idxHandle < g_Sandbox.cHandles
-        && g_Sandbox.papHandles[idxHandle] != NULL)
-    {
-        fRet = CloseHandle(hObject);
-        if (fRet)
-        {
-            PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle];
-            g_Sandbox.papHandles[idxHandle] = NULL;
-            g_Sandbox.cActiveHandles--;
+    if (idxHandle < g_Sandbox.cHandles)
+    {
+        PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle];
+        if (pHandle)
+        {
+            /* Prevent the closing of the standard output and error handles. */
+            if (   pHandle->enmType != KWHANDLETYPE_OUTPUT_BUF
+                || idxHandle != KW_HANDLE_TO_INDEX(pHandle->hHandle))
+            {
+                fRet = CloseHandle(hObject);
+                if (fRet)
+                {
+                    PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle];
+                    g_Sandbox.papHandles[idxHandle] = NULL;
+                    g_Sandbox.cActiveHandles--;
+                    kHlpAssert(g_Sandbox.cActiveHandles >= g_Sandbox.cFixedHandles);
+                    if (--pHandle->cRefs == 0)
+                    {
 #ifdef WITH_TEMP_MEMORY_FILES
-            if (pHandle->enmType == KWHANDLETYPE_TEMP_FILE)
-            {
-                kHlpAssert(pHandle->u.pTempFile->cActiveHandles > 0);
-                pHandle->u.pTempFile->cActiveHandles--;
-            }
+                        if (pHandle->enmType == KWHANDLETYPE_TEMP_FILE)
+                        {
+                            kHlpAssert(pHandle->u.pTempFile->cActiveHandles > 0);
+                            pHandle->u.pTempFile->cActiveHandles--;
+                        }
 #endif
-            kHlpFree(pHandle);
-            KWFS_LOG(("CloseHandle(%p) -> TRUE [intercepted handle]\n", hObject));
-        }
-        else
-            KWFS_LOG(("CloseHandle(%p) -> FALSE [intercepted handle] err=%u!\n", hObject, GetLastError()));
-    }
-    else
-    {
-        KWFS_LOG(("CloseHandle(%p)\n", hObject));
-        fRet = CloseHandle(hObject);
-    }
+                        kHlpFree(pHandle);
+                        KWFS_LOG(("CloseHandle(%p) -> TRUE [intercepted handle, freed]\n", hObject));
+                    }
+                    else
+                        KWFS_LOG(("CloseHandle(%p) -> TRUE [intercepted handle, not freed]\n", hObject));
+                }
+                else
+                    KWFS_LOG(("CloseHandle(%p) -> FALSE [intercepted handle] err=%u!\n", hObject, GetLastError()));
+            }
+            else
+            {
+                KWFS_LOG(("CloseHandle(%p) -> TRUE [intercepted handle] Ignored closing of std%s!\n",
+                          hObject, hObject == g_Sandbox.StdErr.hOutput ? "err" : "out"));
+                fRet = TRUE;
+            }
+            return fRet;
+        }
+    }
+
+    fRet = CloseHandle(hObject);
+    KWFS_LOG(("CloseHandle(%p) -> %d\n", hObject, fRet));
     return fRet;
 }
@@ -5988,4 +6202,5 @@
     if (pSandbox->Combined.cwcBuf > 0)
     {
+        KWOUT_LOG(("kwSandboxConsoleFlushCombined: %u wchars\n", pSandbox->Combined.cwcBuf));
         kwSandboxConsoleWriteIt(pSandbox, pSandbox->Combined.wszBuf, pSandbox->Combined.cwcBuf);
         pSandbox->Combined.cwcBuf = 0;
@@ -6025,6 +6240,7 @@
  * @param   pSandbox            The sandbox.
  * @param   pLineBuf            The line buffer.
- */
-static void kwSandboxConsoleFinalFlushLineBuf(PKWSANDBOX pSandbox, PKWCONSOLEOUTPUTLINE pLineBuf)
+ * @param   pszName             The line buffer name (for logging)
+ */
+static void kwSandboxConsoleFinalFlushLineBuf(PKWSANDBOX pSandbox, PKWOUTPUTSTREAMBUF pLineBuf, const char *pszName)
 {
     if (pLineBuf->fIsConsole)
@@ -6032,4 +6248,6 @@
         if (pLineBuf->u.Con.cwcBuf > 0)
         {
+            KWOUT_LOG(("kwSandboxConsoleFinalFlushLineBuf: %s: %u wchars\n", pszName, pLineBuf->u.Con.cwcBuf));
+
             if (pLineBuf->u.Con.cwcBuf < pLineBuf->u.Con.cwcBufAlloc)
             {
@@ -6045,9 +6263,13 @@
         }
     }
+#ifdef WITH_STD_OUT_ERR_BUFFERING
     else if (pLineBuf->u.Fully.cchBuf > 0)
     {
+        KWOUT_LOG(("kwSandboxConsoleFinalFlushLineBuf: %s: %u bytes\n", pszName, pLineBuf->u.Fully.cchBuf));
+
         kwSandboxOutBufWriteIt(pLineBuf->hBackup, pLineBuf->u.Fully.pchBuf, pLineBuf->u.Fully.cchBuf);
         pLineBuf->u.Fully.cchBuf = 0;
     }
+#endif
 }
 
@@ -6092,18 +6314,23 @@
                     if (fOk)
                     {
+                        KWOUT_LOG(("kwSandboxConsoleFlushAll: Dropping '%*.*ls in combined console buffer\n",
+                                   pSandbox->Combined.cwcBuf, pSandbox->Combined.cwcBuf, pSandbox->Combined.wszBuf));
                         pSandbox->Combined.cwcBuf = 0;
                         return;
                     }
                 }
-            }
-        }
+                KWOUT_LOG(("kwSandboxConsoleFlushAll: Unable to drop '%*.*ls in combined console buffer\n",
+                           pSandbox->Combined.cwcBuf, pSandbox->Combined.cwcBuf, pSandbox->Combined.wszBuf));
+            }
+        }
+#ifdef WITH_STD_OUT_ERR_BUFFERING
         /*
-         * Otherwise, it goes to standard error.
+         * Otherwise, it goes to standard output (redirected).
          */
-        else if (   pSandbox->StdOut.u.Fully.cchBuf == 0
-                 && pSandbox->StdErr.u.Fully.cchBuf >= 3)
-        {
-            char const *pchBuf = pSandbox->StdErr.u.Fully.pchBuf;
-            KI32        off    = pSandbox->StdErr.u.Fully.cchBuf - 1;
+        else if (   pSandbox->StdErr.u.Fully.cchBuf == 0
+                 && pSandbox->StdOut.u.Fully.cchBuf >= 3)
+        {
+            char const *pchBuf = pSandbox->StdOut.u.Fully.pchBuf;
+            KI32        off    = pSandbox->StdOut.u.Fully.cchBuf - 1;
             kHlpAssert(pSandbox->Combined.cFlushes == 0 && pSandbox->Combined.cwcBuf == 0); /* unused! */
 
@@ -6126,9 +6353,14 @@
                 if (fOk)
                 {
-                    pSandbox->StdErr.u.Fully.cchBuf = 0;
+                    KWOUT_LOG(("kwSandboxConsoleFlushAll: Dropping '%*.*s in stdout buffer\n",
+                               pSandbox->StdOut.u.Fully.cchBuf, pSandbox->StdOut.u.Fully.cchBuf, pchBuf));
+                    pSandbox->StdOut.u.Fully.cchBuf = 0;
                     return;
                 }
             }
-        }
+            KWOUT_LOG(("kwSandboxConsoleFlushAll: Unable to drop '%*.*s in stdout buffer\n",
+                       pSandbox->StdOut.u.Fully.cchBuf, pSandbox->StdOut.u.Fully.cchBuf, pchBuf));
+        }
+#endif
     }
 
@@ -6136,6 +6368,6 @@
      * Flush the two line buffer, the the combined buffer.
      */
-    kwSandboxConsoleFinalFlushLineBuf(pSandbox, &pSandbox->StdErr);
-    kwSandboxConsoleFinalFlushLineBuf(pSandbox, &pSandbox->StdOut);
+    kwSandboxConsoleFinalFlushLineBuf(pSandbox, &pSandbox->StdErr, "StdErr");
+    kwSandboxConsoleFinalFlushLineBuf(pSandbox, &pSandbox->StdOut, "StdOut");
     kwSandboxConsoleFlushCombined(pSandbox);
 }
@@ -6150,5 +6382,5 @@
  * @param   cwcToWrite          The number of wchar_t's in the buffer.
  */
-static void kwSandboxConsoleWriteW(PKWSANDBOX pSandbox, PKWCONSOLEOUTPUTLINE pLineBuf, wchar_t const *pwcBuffer, KU32 cwcToWrite)
+static void kwSandboxConsoleWriteW(PKWSANDBOX pSandbox, PKWOUTPUTSTREAMBUF pLineBuf, wchar_t const *pwcBuffer, KU32 cwcToWrite)
 {
     kHlpAssert(pLineBuf->fIsConsole);
@@ -6316,5 +6548,5 @@
  * @param   cchToWrite          How much to write.
  */
-static void kwSandboxConsoleWriteA(PKWSANDBOX pSandbox, PKWCONSOLEOUTPUTLINE pLineBuf, const char *pchBuffer, KU32 cchToWrite)
+static void kwSandboxConsoleWriteA(PKWSANDBOX pSandbox, PKWOUTPUTSTREAMBUF pLineBuf, const char *pchBuffer, KU32 cchToWrite)
 {
     /*
@@ -6374,6 +6606,6 @@
                                              PVOID pvReserved)
 {
-    BOOL                    fRc;
-    PKWCONSOLEOUTPUTLINE    pLineBuf;
+    BOOL                fRc;
+    PKWOUTPUTSTREAMBUF  pLineBuf;
     kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
 
@@ -6386,6 +6618,6 @@
         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));
+        KWOUT_LOG(("WriteConsoleA: %p, %p LB %#x (%*.*s), %p, %p -> TRUE [cached]\n",
+                   hConOutput, pvBuffer, cbToWrite, cbToWrite, cbToWrite, pvBuffer, pcbWritten, pvReserved));
         if (pcbWritten)
             *pcbWritten = cbToWrite;
@@ -6395,6 +6627,6 @@
     {
         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));
+        KWOUT_LOG(("WriteConsoleA: %p, %p LB %#x (%*.*s), %p, %p -> %d !fallback!\n",
+                   hConOutput, pvBuffer, cbToWrite, cbToWrite, cbToWrite, pvBuffer, pcbWritten, pvReserved, fRc));
     }
     return fRc;
@@ -6406,6 +6638,6 @@
                                              PVOID pvReserved)
 {
-    BOOL                    fRc;
-    PKWCONSOLEOUTPUTLINE    pLineBuf;
+    BOOL                fRc;
+    PKWOUTPUTSTREAMBUF  pLineBuf;
     kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
 
@@ -6420,6 +6652,6 @@
         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));
+        KWOUT_LOG(("WriteConsoleW: %p, %p LB %#x (%*.*ls), %p, %p -> TRUE [cached]\n",
+                   hConOutput, pvBuffer, cwcToWrite, cwcToWrite, cwcToWrite, pvBuffer, pcwcWritten, pvReserved));
         if (pcwcWritten)
             *pcwcWritten = cwcToWrite;
@@ -6429,6 +6661,6 @@
     {
         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));
+        KWOUT_LOG(("WriteConsoleW: %p, %p LB %#x (%*.*ls), %p, %p -> %d !fallback!\n",
+                   hConOutput, pvBuffer, cwcToWrite, cwcToWrite, cwcToWrite, pvBuffer, pcwcWritten, pvReserved, fRc));
     }
     return fRc;
@@ -7128,4 +7360,5 @@
     { TUPLE("SetFilePointer"),              NULL,       (KUPTR)kwSandbox_Kernel32_SetFilePointer },
     { TUPLE("SetFilePointerEx"),            NULL,       (KUPTR)kwSandbox_Kernel32_SetFilePointerEx },
+    { TUPLE("DuplicateHandle"),             NULL,       (KUPTR)kwSandbox_Kernel32_DuplicateHandle },
     { TUPLE("CloseHandle"),                 NULL,       (KUPTR)kwSandbox_Kernel32_CloseHandle },
     { TUPLE("GetFileAttributesA"),          NULL,       (KUPTR)kwSandbox_Kernel32_GetFileAttributesA },
@@ -7251,4 +7484,5 @@
     { TUPLE("SetFilePointer"),              NULL,       (KUPTR)kwSandbox_Kernel32_SetFilePointer },
     { TUPLE("SetFilePointerEx"),            NULL,       (KUPTR)kwSandbox_Kernel32_SetFilePointerEx },
+    { TUPLE("DuplicateHandle"),             NULL,       (KUPTR)kwSandbox_Kernel32_DuplicateHandle },
     { TUPLE("CloseHandle"),                 NULL,       (KUPTR)kwSandbox_Kernel32_CloseHandle },
     { TUPLE("GetFileAttributesA"),          NULL,       (KUPTR)kwSandbox_Kernel32_GetFileAttributesA },
@@ -7466,8 +7700,10 @@
  * @param   pSandbox            The sandbox.
  * @param   pHandle             The handle.
- */
-static KBOOL kwSandboxHandleTableEnter(PKWSANDBOX pSandbox, PKWHANDLE pHandle)
-{
-    KUPTR const idxHandle = KW_HANDLE_TO_INDEX(pHandle->hHandle);
+ * @param   hHandle             The handle value to enter it under (for the
+ *                              duplicate handle API).
+ */
+static KBOOL kwSandboxHandleTableEnter(PKWSANDBOX pSandbox, PKWHANDLE pHandle, HANDLE hHandle)
+{
+    KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hHandle);
     kHlpAssertReturn(idxHandle < KW_HANDLE_MAX, K_FALSE);
 
@@ -7562,4 +7798,5 @@
 {
     PPEB pPeb = kwSandboxGetProcessEnvironmentBlock();
+    PMY_RTL_USER_PROCESS_PARAMETERS pProcParams = (PMY_RTL_USER_PROCESS_PARAMETERS)pPeb->ProcessParameters;
     wchar_t *pwcPool;
     KSIZE cbStrings;
@@ -7577,12 +7814,12 @@
 #ifdef WITH_CONSOLE_OUTPUT_BUFFERING
     if (pSandbox->StdOut.fIsConsole)
-        pSandbox->StdOut.u.Con.cwcBuf = 0;
+        pSandbox->StdOut.u.Con.cwcBuf   = 0;
     else
         pSandbox->StdOut.u.Fully.cchBuf = 0;
     if (pSandbox->StdErr.fIsConsole)
-        pSandbox->StdErr.u.Con.cwcBuf = 0;
+        pSandbox->StdErr.u.Con.cwcBuf   = 0;
     else
         pSandbox->StdErr.u.Fully.cchBuf = 0;
-    pSandbox->Combined.cwcBuf = 0;
+    pSandbox->Combined.cwcBuf   = 0;
     pSandbox->Combined.cFlushes = 0;
 #endif
@@ -7620,7 +7857,7 @@
     cwc = kwStrToUtf16(pSandbox->pszCmdLine, pSandbox->pwszCmdLine, cbStrings / sizeof(wchar_t));
 
-    pSandbox->SavedCommandLine = pPeb->ProcessParameters->CommandLine;
-    pPeb->ProcessParameters->CommandLine.Buffer = pSandbox->pwszCmdLine;
-    pPeb->ProcessParameters->CommandLine.Length = (USHORT)cwc * sizeof(wchar_t);
+    pSandbox->SavedCommandLine = pProcParams->CommandLine;
+    pProcParams->CommandLine.Buffer = pSandbox->pwszCmdLine;
+    pProcParams->CommandLine.Length = (USHORT)cwc * sizeof(wchar_t);
 
     /*
@@ -7697,5 +7934,4 @@
     PKWEXITCALLACK              pExitCallback;
 
-
     /*
      * First stuff that may cause code to run.
@@ -7752,4 +7988,52 @@
      * Then free resources associated with the sandbox run.
      */
+
+    /* Open handles, except fixed handles (stdout and stderr). */
+    if (pSandbox->cActiveHandles > pSandbox->cFixedHandles)
+    {
+        KU32 idxHandle = pSandbox->cHandles;
+        while (idxHandle-- > 0)
+            if (pSandbox->papHandles[idxHandle] == NULL)
+            { /* likely */ }
+            else
+            {
+                PKWHANDLE pHandle = pSandbox->papHandles[idxHandle];
+                if (   pHandle->enmType != KWHANDLETYPE_OUTPUT_BUF
+                    || idxHandle != KW_HANDLE_TO_INDEX(pHandle->hHandle) )
+                {
+                    pSandbox->papHandles[idxHandle] = NULL;
+                    pSandbox->cLeakedHandles++;
+
+                    switch (pHandle->enmType)
+                    {
+                        case KWHANDLETYPE_FSOBJ_READ_CACHE:
+                            KWFS_LOG(("Closing leaked read cache handle: %#x/%p cRefs=%d\n",
+                                      idxHandle, pHandle->hHandle, pHandle->cRefs));
+                            break;
+                        case KWHANDLETYPE_OUTPUT_BUF:
+                            KWFS_LOG(("Closing leaked output buf handle: %#x/%p cRefs=%d\n",
+                                      idxHandle, pHandle->hHandle, pHandle->cRefs));
+                            break;
+                        case KWHANDLETYPE_TEMP_FILE:
+                            KWFS_LOG(("Closing leaked temp file  handle: %#x/%p cRefs=%d\n",
+                                      idxHandle, pHandle->hHandle, pHandle->cRefs));
+                            pHandle->u.pTempFile->cActiveHandles--;
+                            break;
+                        case KWHANDLETYPE_TEMP_FILE_MAPPING:
+                            KWFS_LOG(("Closing leaked temp mapping handle: %#x/%p cRefs=%d\n",
+                                      idxHandle, pHandle->hHandle, pHandle->cRefs));
+                            pHandle->u.pTempFile->cActiveHandles--;
+                            break;
+                        default:
+                            kHlpAssertFailed();
+                    }
+                    if (--pHandle->cRefs == 0)
+                        kHlpFree(pHandle);
+                    if (--pSandbox->cActiveHandles == pSandbox->cFixedHandles)
+                        break;
+                }
+            }
+        kHlpAssert(pSandbox->cActiveHandles == pSandbox->cFixedHandles);
+    }
 
 #ifdef WITH_TEMP_MEMORY_FILES
@@ -7831,4 +8115,5 @@
     if (GetProcessMemoryInfo(GetCurrentProcess(), &MemInfo, sizeof(MemInfo)))
     {
+        /** @todo make the limit dynamic and user configurable. */
 #if K_ARCH_BITS >= 64
         if (MemInfo.WorkingSetSize >= 512*1024*1024)
@@ -7838,11 +8123,31 @@
         {
             KW_LOG(("WorkingSetSize = %#x - > restart next time.\n", MemInfo.WorkingSetSize));
-            //fprintf(stderr, "WorkingSetSize = %#x - > restart next time.\n", MemInfo.WorkingSetSize);
             g_fRestart = K_TRUE;
         }
     }
-}
-
-
+
+    /*
+     * The CRT has a max of 8192 handles, so we better restart after a while if
+     * someone is leaking handles or we risk running out of descriptors.
+     *
+     * Note! We only detect leaks for handles we intercept.  In the case of CL.EXE
+     *       doing _dup2(1, 2) (stderr ==> stdout), there isn't actually a leak.
+     */
+    if (pSandbox->cLeakedHandles > 6000)
+    {
+        KW_LOG(("LeakedHandles = %#x - > restart next time.\n", pSandbox->cLeakedHandles));
+        g_fRestart = K_TRUE;
+    }
+}
+
+
+/**
+ * Does essential cleanups and restoring, anything externally visible.
+ *
+ * All cleanups that aren't externally visible are postponed till after we've
+ * informed kmk of the result, so it can be done in the dead time between jobs.
+ *
+ * @param   pSandbox            The sandbox.
+ */
 static void kwSandboxCleanup(PKWSANDBOX pSandbox)
 {
@@ -7851,35 +8156,8 @@
      */
     PPEB pPeb = kwSandboxGetProcessEnvironmentBlock();
-    pPeb->ProcessParameters->CommandLine = pSandbox->SavedCommandLine;
-
-    /*
-     * Kill all open handles.
-     */
-    if (pSandbox->cActiveHandles > 0)
-    {
-        KU32 i = pSandbox->cHandles;
-        while (i-- > 0)
-            if (pSandbox->papHandles[i] == NULL)
-            { /* likely */ }
-            else
-            {
-                PKWHANDLE pHandle = pSandbox->papHandles[i];
-                pSandbox->papHandles[i] = NULL;
-                switch (pHandle->enmType)
-                {
-                    case KWHANDLETYPE_FSOBJ_READ_CACHE:
-                        break;
-                    case KWHANDLETYPE_TEMP_FILE:
-                    case KWHANDLETYPE_TEMP_FILE_MAPPING:
-                        pHandle->u.pTempFile->cActiveHandles--;
-                        break;
-                    default:
-                        kHlpAssertFailed();
-                }
-                kHlpFree(pHandle);
-                if (--pSandbox->cActiveHandles == 0)
-                    break;
-            }
-    }
+    PMY_RTL_USER_PROCESS_PARAMETERS pProcParams = (PMY_RTL_USER_PROCESS_PARAMETERS)pPeb->ProcessParameters;
+    pProcParams->CommandLine    = pSandbox->SavedCommandLine;
+    pProcParams->StandardOutput = pSandbox->StdOut.hOutput;
+    pProcParams->StandardError  = pSandbox->StdErr.hOutput; /* CL.EXE messes with this one. */
 }
 
@@ -8455,4 +8733,8 @@
     }
 
+# ifdef WITH_LOG_FILE
+    if (g_hLogFile != INVALID_HANDLE_VALUE && g_hLogFile != NULL)
+        CloseHandle(g_hLogFile);
+# endif
     return rcExit;
 }
@@ -8475,4 +8757,5 @@
     PPEB                            pPeb           = kwSandboxGetProcessEnvironmentBlock();
     PMY_RTL_USER_PROCESS_PARAMETERS pProcessParams = (PMY_RTL_USER_PROCESS_PARAMETERS)pPeb->ProcessParameters;
+    DWORD                           dwType;
 #endif
 
@@ -8504,16 +8787,54 @@
      * Get and duplicate the console handles.
      */
+    /* Standard output. */
     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;
-
+    dwType = GetFileType(g_Sandbox.StdOut.hOutput);
+    g_Sandbox.StdOut.fIsConsole = dwType == FILE_TYPE_CHAR;
+    g_Sandbox.StdOut.fFileType  = (dwType & ~FILE_TYPE_REMOTE) < 0xf
+                                ? (KU8)((dwType & ~FILE_TYPE_REMOTE) | (dwType >> 8)) : KU8_MAX;
+    g_Sandbox.HandleStdOut.enmType         = KWHANDLETYPE_OUTPUT_BUF;
+    g_Sandbox.HandleStdOut.cRefs           = 0x10001;
+    g_Sandbox.HandleStdOut.dwDesiredAccess = GENERIC_WRITE;
+    g_Sandbox.HandleStdOut.u.pOutBuf       = &g_Sandbox.StdOut;
+    g_Sandbox.HandleStdOut.hHandle         = g_Sandbox.StdOut.hOutput;
+    if (g_Sandbox.StdOut.hOutput != INVALID_HANDLE_VALUE)
+    {
+        if (kwSandboxHandleTableEnter(&g_Sandbox, &g_Sandbox.HandleStdOut, g_Sandbox.StdOut.hOutput))
+            g_Sandbox.cFixedHandles++;
+        else
+            return kwErrPrintfRc(3, "kwSandboxHandleTableEnter failed for StdOut (%p)!\n", g_Sandbox.StdOut.hOutput);
+    }
+    KWOUT_LOG(("StdOut: hOutput=%p (%p) fIsConsole=%d dwType=%#x\n",
+               g_Sandbox.StdOut.hOutput, g_Sandbox.StdOut.hBackup, g_Sandbox.StdOut.fIsConsole, dwType));
+
+    /* Standard error. */
     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;
-
+    dwType = GetFileType(g_Sandbox.StdErr.hOutput);
+    g_Sandbox.StdErr.fIsConsole = dwType == FILE_TYPE_CHAR;
+    g_Sandbox.StdErr.fFileType  = (dwType & ~FILE_TYPE_REMOTE) < 0xf
+                                ? (KU8)((dwType & ~FILE_TYPE_REMOTE) | (dwType >> 8)) : KU8_MAX;
+    g_Sandbox.HandleStdErr.enmType         = KWHANDLETYPE_OUTPUT_BUF;
+    g_Sandbox.HandleStdErr.cRefs           = 0x10001;
+    g_Sandbox.HandleStdErr.dwDesiredAccess = GENERIC_WRITE;
+    g_Sandbox.HandleStdErr.u.pOutBuf       = &g_Sandbox.StdErr;
+    g_Sandbox.HandleStdErr.hHandle         = g_Sandbox.StdErr.hOutput;
+    if (   g_Sandbox.StdErr.hOutput != INVALID_HANDLE_VALUE
+        && g_Sandbox.StdErr.hOutput != g_Sandbox.StdOut.hOutput)
+    {
+        if (kwSandboxHandleTableEnter(&g_Sandbox, &g_Sandbox.HandleStdErr, g_Sandbox.StdErr.hOutput))
+            g_Sandbox.cFixedHandles++;
+        else
+            return kwErrPrintfRc(3, "kwSandboxHandleTableEnter failed for StdErr (%p)!\n", g_Sandbox.StdErr.hOutput);
+    }
+    KWOUT_LOG(("StdErr: hOutput=%p (%p) fIsConsole=%d dwType=%#x\n",
+               g_Sandbox.StdErr.hOutput, g_Sandbox.StdErr.hBackup, g_Sandbox.StdErr.fIsConsole, dwType));
+
+    /* Combined console buffer. */
     if (g_Sandbox.StdErr.fIsConsole)
     {
@@ -8531,5 +8852,6 @@
         g_Sandbox.Combined.uCodepage = CP_ACP;
     }
-#endif
+    KWOUT_LOG(("Combined: hOutput=%p uCodepage=%d\n", g_Sandbox.Combined.hOutput, g_Sandbox.Combined.uCodepage));
+#endif /* WITH_CONSOLE_OUTPUT_BUFFERING */
 
 
@@ -8674,4 +8996,8 @@
 
         CloseHandle(hPipe);
+# ifdef WITH_LOG_FILE
+        if (g_hLogFile != INVALID_HANDLE_VALUE && g_hLogFile != NULL)
+            CloseHandle(g_hLogFile);
+# endif
         return rc > 0 ? 0 : 1;
     }
Index: /trunk/src/kmk/kmkbuiltin/redirect.c
===================================================================
--- /trunk/src/kmk/kmkbuiltin/redirect.c	(revision 2915)
+++ /trunk/src/kmk/kmkbuiltin/redirect.c	(revision 2916)
@@ -387,9 +387,15 @@
     int         aFdTries[32];
     int         cTries;
+    int         fdOpened;
+
+#ifdef KBUILD_OS_WINDOWS
+    if (strcmp(pszFilename, "/dev/null") == 0)
+        pszFilename = "nul";
+#endif
 
     /* Open it first. */
-    int fdOpened = open(pszFilename, fOpen | fNoInherit, fMode);
+    fdOpened = open(pszFilename, fOpen | fNoInherit, fMode);
     if (fdOpened < 0)
-        return err(9, "open(%s,%#x,) failed", pszFilename, fOpen);
+        return err(-1, "open(%s,%#x,) failed", pszFilename, fOpen);
 
     /* Check for conflicts. */
@@ -434,5 +440,5 @@
         else
         {
-            err(9, "open(%s,%#x,) #%u failed", pszFilename, cTries + 1, fOpen);
+            err(-1, "open(%s,%#x,) #%u failed", pszFilename, cTries + 1, fOpen);
             break;
         }
@@ -444,5 +450,5 @@
      */
     if (fdOpened >= 0)
-        errx(9, "failed to find a conflict free file descriptor for '%s'!", pszFilename);
+        errx(-1, "failed to find a conflict free file descriptor for '%s'!", pszFilename);
 
     while (cTries-- > 0)
@@ -1580,4 +1586,6 @@
 #endif
                 }
+                else
+                    rcExit = 9;
             }
         }
Index: /trunk/src/kmk/main.c
===================================================================
--- /trunk/src/kmk/main.c	(revision 2915)
+++ /trunk/src/kmk/main.c	(revision 2916)
@@ -920,4 +920,5 @@
 
 #ifdef WINDOWS32
+# ifndef KMK
 /*
  * HANDLE runtime exceptions by avoiding a requestor on the GUI. Capture
@@ -994,4 +995,5 @@
 #endif
 }
+# endif /* !KMK */
 
 /*
@@ -1381,5 +1383,7 @@
 
 # ifndef ELECTRIC_HEAP /* Drop this because it prevents JIT debugging. */
+#  ifndef KMK /* Don't want none of this crap. */
   SetUnhandledExceptionFilter(handle_runtime_exceptions);
+#  endif
 # endif /* !ELECTRIC_HEAP */
 
