on windows, the return values from wait() and waitpid() don't
[p5sagit/p5-mst-13.2.git] / win32 / win32.c
index 710a047..56ebdaf 100644 (file)
 #define Win32_Winsock
 #endif
 #include <windows.h>
+#ifndef __MINGW32__    /* GCC/Mingw32-2.95.2 forgot the WINAPI on CommandLineToArgvW() */
+#  include <shellapi.h>
+#else
+   LPWSTR* WINAPI CommandLineToArgvW(LPCWSTR lpCommandLine, int * pNumArgs);
+#endif
 #include <winnt.h>
 #include <io.h>
 
@@ -48,7 +53,6 @@
 #else
 #include <utime.h>
 #endif
-
 #ifdef __GNUC__
 /* Mingw32 defaults to globing command line 
  * So we turn it off like this:
@@ -57,7 +61,12 @@ int _CRT_glob = 0;
 #endif
 
 #if defined(__MINGW32__)
-#  define _stat stat
+/* Mingw32 is missing some prototypes */
+FILE * _wfopen(LPCWSTR wszFileName, LPCWSTR wszMode);
+FILE * _wfdopen(int nFd, LPCWSTR wszMode);
+FILE * _freopen(LPCWSTR wszFileName, LPCWSTR wszMode, FILE * pOldStream);
+int _flushall();
+int _fcloseall();
 #endif
 
 #if defined(__BORLANDC__)
@@ -74,6 +83,8 @@ int _CRT_glob = 0;
 #  define win32_get_privlib g_win32_get_privlib
 #  undef win32_get_sitelib
 #  define win32_get_sitelib g_win32_get_sitelib
+#  undef win32_get_vendorlib
+#  define win32_get_vendorlib g_win32_get_vendorlib
 #  undef do_spawn
 #  define do_spawn g_do_spawn
 #  undef getlogin
@@ -97,6 +108,9 @@ static char *                get_emd_part(SV **leading, char *trailing, ...);
 static void            remove_dead_process(long deceased);
 static long            find_pid(int pid);
 static char *          qualified_path(const char *cmd);
+static char *          win32_get_xlib(const char *pl, const char *xlib,
+                                      const char *libname);
+
 #ifdef USE_ITHREADS
 static void            remove_dead_pseudo_process(long child);
 static long            find_pseudo_pid(int pid);
@@ -123,6 +137,30 @@ IsWinNT(void)
     return (win32_os_id() == VER_PLATFORM_WIN32_NT);
 }
 
+EXTERN_C void
+set_w32_module_name(void)
+{
+    char* ptr;
+    GetModuleFileName((HMODULE)((w32_perldll_handle == INVALID_HANDLE_VALUE)
+                               ? GetModuleHandle(NULL)
+                               : w32_perldll_handle),
+                     w32_module_name, sizeof(w32_module_name));
+
+    /* try to get full path to binary (which may be mangled when perl is
+     * run from a 16-bit app) */
+    /*PerlIO_printf(Perl_debug_log, "Before %s\n", w32_module_name);*/
+    (void)win32_longpath(w32_module_name);
+    /*PerlIO_printf(Perl_debug_log, "After  %s\n", w32_module_name);*/
+
+    /* normalize to forward slashes */
+    ptr = w32_module_name;
+    while (*ptr) {
+       if (*ptr == '\\')
+           *ptr = '/';
+       ++ptr;
+    }
+}
+
 /* *svp (if non-NULL) is expected to be POK (valid allocated SvPVX(*svp)) */
 static char*
 get_regstr_from(HKEY hkey, const char *valuename, SV **svp)
@@ -138,7 +176,9 @@ get_regstr_from(HKEY hkey, const char *valuename, SV **svp)
     if (retval == ERROR_SUCCESS) {
        DWORD datalen;
        retval = RegQueryValueEx(handle, valuename, 0, &type, NULL, &datalen);
-       if (retval == ERROR_SUCCESS && type == REG_SZ) {
+       if (retval == ERROR_SUCCESS
+           && (type == REG_SZ || type == REG_EXPAND_SZ))
+       {
            dTHXo;
            if (!*svp)
                *svp = sv_2mortal(newSVpvn("",0));
@@ -185,24 +225,7 @@ get_emd_part(SV **prev_pathp, char *trailing_path, ...)
     baselen = strlen(base);
 
     if (!*w32_module_name) {
-       GetModuleFileName((HMODULE)((w32_perldll_handle == INVALID_HANDLE_VALUE)
-                                   ? GetModuleHandle(NULL)
-                                   : w32_perldll_handle),
-                         w32_module_name, sizeof(w32_module_name));
-
-       /* try to get full path to binary (which may be mangled when perl is
-        * run from a 16-bit app) */
-       /*PerlIO_printf(Perl_debug_log, "Before %s\n", w32_module_name);*/
-       (void)win32_longpath(w32_module_name);
-       /*PerlIO_printf(Perl_debug_log, "After  %s\n", w32_module_name);*/
-
-       /* normalize to forward slashes */
-       ptr = w32_module_name;
-       while (*ptr) {
-           if (*ptr == '\\')
-               *ptr = '/';
-           ++ptr;
-       }
+       set_w32_module_name();
     }
     strcpy(mod_name, w32_module_name);
     ptr = strrchr(mod_name, '/');
@@ -248,7 +271,7 @@ get_emd_part(SV **prev_pathp, char *trailing_path, ...)
 }
 
 char *
-win32_get_privlib(char *pl)
+win32_get_privlib(const char *pl)
 {
     dTHXo;
     char *stdlib = "lib";
@@ -264,11 +287,10 @@ win32_get_privlib(char *pl)
     return get_emd_part(&sv, stdlib, ARCHNAME, "bin", Nullch);
 }
 
-char *
-win32_get_sitelib(char *pl)
+static char *
+win32_get_xlib(const char *pl, const char *xlib, const char *libname)
 {
     dTHXo;
-    char *sitelib = "sitelib";
     char regstr[40];
     char pathstr[MAX_PATH+1];
     DWORD datalen;
@@ -276,21 +298,22 @@ win32_get_sitelib(char *pl)
     SV *sv1 = Nullsv;
     SV *sv2 = Nullsv;
 
-    /* $HKCU{"sitelib-$]"} || $HKLM{"sitelib-$]"} . ---; */
-    sprintf(regstr, "%s-%s", sitelib, pl);
+    /* $HKCU{"$xlib-$]"} || $HKLM{"$xlib-$]"} . ---; */
+    sprintf(regstr, "%s-%s", xlib, pl);
     (void)get_regstr(regstr, &sv1);
 
-    /* $sitelib .=
-     * ";$EMD/" . ((-d $EMD/../../../$]) ? "../../.." : "../.."). "/site/$]/lib";  */
-    sprintf(pathstr, "site/%s/lib", pl);
+    /* $xlib .=
+     * ";$EMD/" . ((-d $EMD/../../../$]) ? "../../.." : "../.."). "/$libname/$]/lib";  */
+    sprintf(pathstr, "%s/%s/lib", libname, pl);
     (void)get_emd_part(&sv1, pathstr, ARCHNAME, "bin", pl, Nullch);
 
-    /* $HKCU{'sitelib'} || $HKLM{'sitelib'} . ---; */
-    (void)get_regstr(sitelib, &sv2);
+    /* $HKCU{$xlib} || $HKLM{$xlib} . ---; */
+    (void)get_regstr(xlib, &sv2);
 
-    /* $sitelib .=
-     * ";$EMD/" . ((-d $EMD/../../../$]) ? "../../.." : "../.."). "/site/lib";  */
-    (void)get_emd_part(&sv2, "site/lib", ARCHNAME, "bin", pl, Nullch);
+    /* $xlib .=
+     * ";$EMD/" . ((-d $EMD/../../../$]) ? "../../.." : "../.."). "/$libname/lib";  */
+    sprintf(pathstr, "%s/lib", libname);
+    (void)get_emd_part(&sv2, pathstr, ARCHNAME, "bin", pl, Nullch);
 
     if (!sv1 && !sv2)
        return Nullch;
@@ -305,6 +328,21 @@ win32_get_sitelib(char *pl)
     return SvPVX(sv1);
 }
 
+char *
+win32_get_sitelib(const char *pl)
+{
+    return win32_get_xlib(pl, "sitelib", "site");
+}
+
+#ifndef PERL_VENDORLIB_NAME
+#  define PERL_VENDORLIB_NAME  "vendor"
+#endif
+
+char *
+win32_get_vendorlib(const char *pl)
+{
+    return win32_get_xlib(pl, "vendorlib", PERL_VENDORLIB_NAME);
+}
 
 static BOOL
 has_shell_metachars(char *ptr)
@@ -671,7 +709,7 @@ win32_opendir(char *filename)
     WIN32_FIND_DATAW   wFindData;
     HANDLE             fh;
     char               buffer[MAX_PATH*2];
-    WCHAR              wbuffer[MAX_PATH];
+    WCHAR              wbuffer[MAX_PATH+1];
     char*              ptr;
 
     len = strlen(filename);
@@ -942,9 +980,9 @@ remove_dead_process(long child)
     if (child >= 0) {
        dTHXo;
        CloseHandle(w32_child_handles[child]);
-       Copy(&w32_child_handles[child+1], &w32_child_handles[child],
+       Move(&w32_child_handles[child+1], &w32_child_handles[child],
             (w32_num_children-child-1), HANDLE);
-       Copy(&w32_child_pids[child+1], &w32_child_pids[child],
+       Move(&w32_child_pids[child+1], &w32_child_pids[child],
             (w32_num_children-child-1), DWORD);
        w32_num_children--;
     }
@@ -969,9 +1007,9 @@ remove_dead_pseudo_process(long child)
     if (child >= 0) {
        dTHXo;
        CloseHandle(w32_pseudo_child_handles[child]);
-       Copy(&w32_pseudo_child_handles[child+1], &w32_pseudo_child_handles[child],
+       Move(&w32_pseudo_child_handles[child+1], &w32_pseudo_child_handles[child],
             (w32_num_pseudo_children-child-1), HANDLE);
-       Copy(&w32_pseudo_child_pids[child+1], &w32_pseudo_child_pids[child],
+       Move(&w32_pseudo_child_pids[child+1], &w32_pseudo_child_pids[child],
             (w32_num_pseudo_children-child-1), DWORD);
        w32_num_pseudo_children--;
     }
@@ -988,6 +1026,8 @@ win32_kill(int pid, int sig)
        /* it is a pseudo-forked child */
        long child = find_pseudo_pid(-pid);
        if (child >= 0) {
+           if (!sig)
+               return 0;
            hProcess = w32_pseudo_child_handles[child];
            if (TerminateThread(hProcess, sig)) {
                remove_dead_pseudo_process(child);
@@ -1000,6 +1040,8 @@ win32_kill(int pid, int sig)
     {
        long child = find_pid(pid);
        if (child >= 0) {
+           if (!sig)
+               return 0;
            hProcess = w32_child_handles[child];
            if (TerminateProcess(hProcess, sig)) {
                remove_dead_process(child);
@@ -1008,9 +1050,13 @@ win32_kill(int pid, int sig)
        }
        else {
            hProcess = OpenProcess(PROCESS_ALL_ACCESS, TRUE, pid);
-           if (hProcess && TerminateProcess(hProcess, sig)) {
-               CloseHandle(hProcess);
-               return 0;
+           if (hProcess) {
+               if (!sig)
+                   return 0;
+               if (TerminateProcess(hProcess, sig)) {
+                   CloseHandle(hProcess);
+                   return 0;
+               }
            }
        }
     }
@@ -1030,13 +1076,14 @@ win32_sleep(unsigned int t)
 }
 
 DllExport int
-win32_stat(const char *path, struct stat *buffer)
+win32_stat(const char *path, struct stat *sbuf)
 {
     dTHXo;
-    char       t[MAX_PATH+1]; 
+    char       buffer[MAX_PATH+1]; 
     int                l = strlen(path);
     int                res;
-    WCHAR      wbuffer[MAX_PATH];
+    WCHAR      wbuffer[MAX_PATH+1];
+    WCHAR*     pwbuffer;
     HANDLE      handle;
     int         nlink = 1;
 
@@ -1045,17 +1092,20 @@ win32_stat(const char *path, struct stat *buffer)
        /* FindFirstFile() and stat() are buggy with a trailing
         * backslash, so change it to a forward slash :-( */
        case '\\':
-           strncpy(t, path, l-1);
-           t[l - 1] = '/';
-           t[l] = '\0';
-           path = t;
+           strncpy(buffer, path, l-1);
+           buffer[l - 1] = '/';
+           buffer[l] = '\0';
+           path = buffer;
            break;
        /* FindFirstFile() is buggy with "x:", so add a dot :-( */
        case ':':
            if (l == 2 && isALPHA(path[0])) {
-               t[0] = path[0]; t[1] = ':'; t[2] = '.'; t[3] = '\0';
+               buffer[0] = path[0];
+               buffer[1] = ':';
+               buffer[2] = '.';
+               buffer[3] = '\0';
                l = 3;
-               path = t;
+               path = buffer;
            }
            break;
        }
@@ -1066,11 +1116,12 @@ win32_stat(const char *path, struct stat *buffer)
     /* This also gives us an opportunity to determine the number of links.    */
     if (USING_WIDE()) {
        A2WHELPER(path, wbuffer, sizeof(wbuffer));
-       wcscpy(wbuffer, PerlDir_mapW(wbuffer));
-       handle = CreateFileW(wbuffer, 0, 0, NULL, OPEN_EXISTING, 0, NULL);
+       pwbuffer = PerlDir_mapW(wbuffer);
+       handle = CreateFileW(pwbuffer, 0, 0, NULL, OPEN_EXISTING, 0, NULL);
     }
     else {
        path = PerlDir_mapA(path);
+       l = strlen(path);
        handle = CreateFileA(path, 0, 0, NULL, OPEN_EXISTING, 0, NULL);
     }
     if (handle != INVALID_HANDLE_VALUE) {
@@ -1080,34 +1131,34 @@ win32_stat(const char *path, struct stat *buffer)
        CloseHandle(handle);
     }
 
-    /* wbuffer or path will be mapped correctly above */
+    /* pwbuffer or path will be mapped correctly above */
     if (USING_WIDE()) {
-       res = _wstat(wbuffer, (struct _stat *)buffer);
+       res = _wstat(pwbuffer, (struct _stat *)sbuf);
     }
     else {
-       res = stat(path, buffer);
+       res = stat(path, sbuf);
     }
-    buffer->st_nlink = nlink;
+    sbuf->st_nlink = nlink;
 
     if (res < 0) {
        /* CRT is buggy on sharenames, so make sure it really isn't.
         * XXX using GetFileAttributesEx() will enable us to set
-        * buffer->st_*time (but note that's not available on the
+        * sbuf->st_*time (but note that's not available on the
         * Windows of 1995) */
        DWORD r;
        if (USING_WIDE()) {
-           r = GetFileAttributesW(wbuffer);
+           r = GetFileAttributesW(pwbuffer);
        }
        else {
            r = GetFileAttributesA(path);
        }
        if (r != 0xffffffff && (r & FILE_ATTRIBUTE_DIRECTORY)) {
-           /* buffer may still contain old garbage since stat() failed */
-           Zero(buffer, 1, struct stat);
-           buffer->st_mode = S_IFDIR | S_IREAD;
+           /* sbuf may still contain old garbage since stat() failed */
+           Zero(sbuf, 1, struct stat);
+           sbuf->st_mode = S_IFDIR | S_IREAD;
            errno = 0;
            if (!(r & FILE_ATTRIBUTE_READONLY))
-               buffer->st_mode |= S_IWRITE | S_IEXEC;
+               sbuf->st_mode |= S_IWRITE | S_IEXEC;
            return 0;
        }
     }
@@ -1117,28 +1168,32 @@ win32_stat(const char *path, struct stat *buffer)
        {
            /* The drive can be inaccessible, some _stat()s are buggy */
            if (USING_WIDE()
-               ? !GetVolumeInformationW(wbuffer,NULL,0,NULL,NULL,NULL,NULL,0)
+               ? !GetVolumeInformationW(pwbuffer,NULL,0,NULL,NULL,NULL,NULL,0)
                : !GetVolumeInformationA(path,NULL,0,NULL,NULL,NULL,NULL,0)) {
                errno = ENOENT;
                return -1;
            }
        }
 #ifdef __BORLANDC__
-       if (S_ISDIR(buffer->st_mode))
-           buffer->st_mode |= S_IWRITE | S_IEXEC;
-       else if (S_ISREG(buffer->st_mode)) {
+       if (S_ISDIR(sbuf->st_mode))
+           sbuf->st_mode |= S_IWRITE | S_IEXEC;
+       else if (S_ISREG(sbuf->st_mode)) {
+           int perms;
            if (l >= 4 && path[l-4] == '.') {
                const char *e = path + l - 3;
                if (strnicmp(e,"exe",3)
                    && strnicmp(e,"bat",3)
                    && strnicmp(e,"com",3)
                    && (IsWin95() || strnicmp(e,"cmd",3)))
-                   buffer->st_mode &= ~S_IEXEC;
+                   sbuf->st_mode &= ~S_IEXEC;
                else
-                   buffer->st_mode |= S_IEXEC;
+                   sbuf->st_mode |= S_IEXEC;
            }
            else
-               buffer->st_mode &= ~S_IEXEC;
+               sbuf->st_mode &= ~S_IEXEC;
+           /* Propagate permissions to _group_ and _others_ */
+           perms = sbuf->st_mode & (S_IREAD|S_IWRITE|S_IEXEC);
+           sbuf->st_mode |= (perms>>3) | (perms>>6);
        }
 #endif
     }
@@ -1228,7 +1283,7 @@ DllExport char *
 win32_getenv(const char *name)
 {
     dTHXo;
-    WCHAR wBuffer[MAX_PATH];
+    WCHAR wBuffer[MAX_PATH+1];
     DWORD needlen;
     SV *curitem = Nullsv;
 
@@ -1392,23 +1447,28 @@ win32_unlink(const char *filename)
     DWORD attrs;
 
     if (USING_WIDE()) {
-       WCHAR wBuffer[MAX_PATH];
+       WCHAR wBuffer[MAX_PATH+1];
+       WCHAR* pwBuffer;
 
        A2WHELPER(filename, wBuffer, sizeof(wBuffer));
-       wcscpy(wBuffer, PerlDir_mapW(wBuffer));
-       attrs = GetFileAttributesW(wBuffer);
+       pwBuffer = PerlDir_mapW(wBuffer);
+       attrs = GetFileAttributesW(pwBuffer);
+       if (attrs == 0xFFFFFFFF)
+           goto fail;
        if (attrs & FILE_ATTRIBUTE_READONLY) {
-           (void)SetFileAttributesW(wBuffer, attrs & ~FILE_ATTRIBUTE_READONLY);
-           ret = _wunlink(wBuffer);
+           (void)SetFileAttributesW(pwBuffer, attrs & ~FILE_ATTRIBUTE_READONLY);
+           ret = _wunlink(pwBuffer);
            if (ret == -1)
-               (void)SetFileAttributesW(wBuffer, attrs);
+               (void)SetFileAttributesW(pwBuffer, attrs);
        }
        else
-           ret = _wunlink(wBuffer);
+           ret = _wunlink(pwBuffer);
     }
     else {
        filename = PerlDir_mapA(filename);
        attrs = GetFileAttributesA(filename);
+       if (attrs == 0xFFFFFFFF)
+           goto fail;
        if (attrs & FILE_ATTRIBUTE_READONLY) {
            (void)SetFileAttributesA(filename, attrs & ~FILE_ATTRIBUTE_READONLY);
            ret = unlink(filename);
@@ -1419,6 +1479,9 @@ win32_unlink(const char *filename)
            ret = unlink(filename);
     }
     return ret;
+fail:
+    errno = ENOENT;
+    return -1;
 }
 
 DllExport int
@@ -1430,13 +1493,14 @@ win32_utime(const char *filename, struct utimbuf *times)
     FILETIME ftAccess;
     FILETIME ftWrite;
     struct utimbuf TimeBuffer;
-    WCHAR wbuffer[MAX_PATH];
+    WCHAR wbuffer[MAX_PATH+1];
+    WCHAR* pwbuffer;
 
     int rc;
     if (USING_WIDE()) {
        A2WHELPER(filename, wbuffer, sizeof(wbuffer));
-       wcscpy(wbuffer, PerlDir_mapW(wbuffer));
-       rc = _wutime(wbuffer, (struct _utimbuf*)times);
+       pwbuffer = PerlDir_mapW(wbuffer);
+       rc = _wutime(pwbuffer, (struct _utimbuf*)times);
     }
     else {
        filename = PerlDir_mapA(filename);
@@ -1454,7 +1518,7 @@ win32_utime(const char *filename, struct utimbuf *times)
 
     /* This will (and should) still fail on readonly files */
     if (USING_WIDE()) {
-       handle = CreateFileW(wbuffer, GENERIC_READ | GENERIC_WRITE,
+       handle = CreateFileW(pwbuffer, GENERIC_READ | GENERIC_WRITE,
                            FILE_SHARE_READ | FILE_SHARE_DELETE, NULL,
                            OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
     }
@@ -1580,13 +1644,17 @@ win32_waitpid(int pid, int *status, int flags)
        long child = find_pseudo_pid(-pid);
        if (child >= 0) {
            HANDLE hThread = w32_pseudo_child_handles[child];
-           DWORD waitcode = WaitForSingleObject(hThread, INFINITE);
-           if (waitcode != WAIT_FAILED) {
+           DWORD timeout = (flags & WNOHANG) ? 0 : INFINITE;
+           DWORD waitcode = WaitForSingleObject(hThread, timeout);
+           if (waitcode == WAIT_TIMEOUT) {
+               return 0;
+           }
+           else if (waitcode != WAIT_FAILED) {
                if (GetExitCodeThread(hThread, &waitcode)) {
                    *status = (int)((waitcode & 0xff) << 8);
                    retval = (int)w32_pseudo_child_pids[child];
                    remove_dead_pseudo_process(child);
-                   return retval;
+                   return -retval;
                }
            }
            else
@@ -1598,14 +1666,18 @@ win32_waitpid(int pid, int *status, int flags)
        long child = find_pid(pid);
        if (child >= 0) {
            HANDLE hProcess = w32_child_handles[child];
-           DWORD waitcode = WaitForSingleObject(hProcess, INFINITE);
-           if (waitcode != WAIT_FAILED) {
-               if (GetExitCodeProcess(hProcess, &waitcode)) {
-                   *status = (int)((waitcode & 0xff) << 8);
-                   retval = (int)w32_child_pids[child];
-                   remove_dead_process(child);
-                   return retval;
-               }
+           DWORD timeout = (flags & WNOHANG) ? 0 : INFINITE;
+           DWORD waitcode = WaitForSingleObject(hProcess, timeout);
+           if (waitcode == WAIT_TIMEOUT) {
+               return 0;
+           }
+           else if (waitcode != WAIT_FAILED) {
+                if (GetExitCodeProcess(hProcess, &waitcode)) {
+                    *status = (int)((waitcode & 0xff) << 8);
+                    retval = (int)w32_child_pids[child];
+                    remove_dead_process(child);
+                    return retval;
+                }
            }
            else
                errno = ECHILD;
@@ -1648,7 +1720,7 @@ win32_wait(int *status)
                *status = (int)((exitcode & 0xff) << 8);
                retval = (int)w32_pseudo_child_pids[i];
                remove_dead_pseudo_process(i);
-               return retval;
+               return -retval;
            }
        }
     }
@@ -1683,6 +1755,8 @@ FAILED:
     return -1;
 }
 
+#ifndef PERL_OBJECT
+
 static UINT timerid = 0;
 
 static VOID CALLBACK TimerProc(HWND win, UINT msg, UINT id, DWORD time)
@@ -1690,12 +1764,14 @@ static VOID CALLBACK TimerProc(HWND win, UINT msg, UINT id, DWORD time)
     dTHXo;
     KillTimer(NULL,timerid);
     timerid=0;  
-    sighandler(14);
+    CALL_FPTR(PL_sighandlerp)(14);
 }
+#endif /* !PERL_OBJECT */
 
 DllExport unsigned int
 win32_alarm(unsigned int sec)
 {
+#ifndef PERL_OBJECT
     /* 
      * the 'obvious' implentation is SetTimer() with a callback
      * which does whatever receiving SIGALRM would do 
@@ -1720,6 +1796,7 @@ win32_alarm(unsigned int sec)
         timerid=0;  
        }
      }
+#endif /* !PERL_OBJECT */
     return 0;
 }
 
@@ -1740,53 +1817,71 @@ win32_crypt(const char *txt, const char *salt)
 #endif
 }
 
-#ifdef USE_FIXED_OSFHANDLE
+/* C doesn't like repeat struct definitions */
+
+#if defined(USE_FIXED_OSFHANDLE) || defined(PERL_MSVCRT_READFIX)
 
-EXTERN_C int __cdecl _alloc_osfhnd(void);
-EXTERN_C int __cdecl _set_osfhnd(int fh, long value);
-EXTERN_C void __cdecl _lock_fhandle(int);
-EXTERN_C void __cdecl _unlock_fhandle(int);
-EXTERN_C void __cdecl _unlock(int);
+#ifndef _CRTIMP
+#define _CRTIMP __declspec(dllimport)
+#endif
 
-#if    (_MSC_VER >= 1000)
-typedef struct {
+/*
+ * Control structure for lowio file handles
+ */
+typedef struct {
     long osfhnd;    /* underlying OS file HANDLE */
     char osfile;    /* attributes of file (e.g., open in text mode?) */
     char pipech;    /* one char buffer for handles opened on pipes */
-#if defined (_MT) && !defined (DLL_FOR_WIN32S)
     int lockinitflag;
     CRITICAL_SECTION lock;
-#endif  /* defined (_MT) && !defined (DLL_FOR_WIN32S) */
-}      ioinfo;
+} ioinfo;
 
-EXTERN_C ioinfo * __pioinfo[];
 
-#define IOINFO_L2E                     5
-#define IOINFO_ARRAY_ELTS      (1 << IOINFO_L2E)
-#define _pioinfo(i)    (__pioinfo[i >> IOINFO_L2E] + (i & (IOINFO_ARRAY_ELTS - 1)))
-#define _osfile(i)     (_pioinfo(i)->osfile)
+/*
+ * Array of arrays of control structures for lowio files.
+ */
+EXTERN_C _CRTIMP ioinfo* __pioinfo[];
+
+/*
+ * Definition of IOINFO_L2E, the log base 2 of the number of elements in each
+ * array of ioinfo structs.
+ */
+#define IOINFO_L2E         5
 
-#else  /* (_MSC_VER >= 1000) */
-extern char _osfile[];
-#endif /* (_MSC_VER >= 1000) */
+/*
+ * Definition of IOINFO_ARRAY_ELTS, the number of elements in ioinfo array
+ */
+#define IOINFO_ARRAY_ELTS   (1 << IOINFO_L2E)
+
+/*
+ * Access macros for getting at an ioinfo struct and its fields from a
+ * file handle
+ */
+#define _pioinfo(i) (__pioinfo[(i) >> IOINFO_L2E] + ((i) & (IOINFO_ARRAY_ELTS - 1)))
+#define _osfhnd(i)  (_pioinfo(i)->osfhnd)
+#define _osfile(i)  (_pioinfo(i)->osfile)
+#define _pipech(i)  (_pioinfo(i)->pipech)
+
+#endif
+
+#ifdef USE_FIXED_OSFHANDLE
 
 #define FOPEN                  0x01    /* file handle open */
+#define FNOINHERIT             0x10    /* file handle opened O_NOINHERIT */
 #define FAPPEND                        0x20    /* file handle opened O_APPEND */
 #define FDEV                   0x40    /* file handle refers to device */
 #define FTEXT                  0x80    /* file handle is in text mode */
 
-#define _STREAM_LOCKS   26             /* Table of stream locks */
-#define _LAST_STREAM_LOCK  (_STREAM_LOCKS+_NSTREAM_-1) /* Last stream lock */
-#define _FH_LOCKS          (_LAST_STREAM_LOCK+1)       /* Table of fh locks */
-
 /***
 *int my_open_osfhandle(long osfhandle, int flags) - open C Runtime file handle
 *
 *Purpose:
 *       This function allocates a free C Runtime file handle and associates
 *       it with the Win32 HANDLE specified by the first parameter. This is a
-*              temperary fix for WIN95's brain damage GetFileType() error on socket
-*              we just bypass that call for socket
+*      temperary fix for WIN95's brain damage GetFileType() error on socket
+*      we just bypass that call for socket
+*
+*      This works with MSVC++ 4.0+ or GCC/Mingw32
 *
 *Entry:
 *       long osfhandle - Win32 HANDLE to associate with C Runtime file handle.
@@ -1800,6 +1895,31 @@ extern char _osfile[];
 *
 *******************************************************************************/
 
+/*
+ * we fake up some parts of the CRT that aren't exported by MSVCRT.dll
+ * this lets sockets work on Win9X with GCC and should fix the problems
+ * with perl95.exe
+ *     -- BKS, 1-23-2000
+*/
+
+/* since we are not doing a dup2(), this works fine */
+
+#define _set_osfhnd(fh, osfh) (void)(_osfhnd(fh) = osfh)
+
+/* create an ioinfo entry, kill its handle, and steal the entry */
+
+static int
+_alloc_osfhnd(void)
+{
+    HANDLE hF = CreateFile("NUL", 0, 0, NULL, OPEN_ALWAYS, 0, NULL);
+    int fh = _open_osfhandle((long)hF, 0);
+    CloseHandle(hF);
+    if (fh == -1)
+        return fh;
+    EnterCriticalSection(&(_pioinfo(fh)->lock));
+    return fh;
+}
+
 static int
 my_open_osfhandle(long osfhandle, int flags)
 {
@@ -1815,6 +1935,9 @@ my_open_osfhandle(long osfhandle, int flags)
     if (flags & O_TEXT)
        fileflags |= FTEXT;
 
+    if (flags & O_NOINHERIT)
+       fileflags |= FNOINHERIT;
+
     /* attempt to allocate a C Runtime file handle */
     if ((fh = _alloc_osfhnd()) == -1) {
        errno = EMFILE;         /* too many open files */
@@ -1827,18 +1950,12 @@ my_open_osfhandle(long osfhandle, int flags)
 
     fileflags |= FOPEN;                /* mark as open */
 
-#if (_MSC_VER >= 1000)
     _osfile(fh) = fileflags;   /* set osfile entry */
-    _unlock_fhandle(fh);
-#else
-    _osfile[fh] = fileflags;   /* set osfile entry */
-    _unlock(fh+_FH_LOCKS);             /* unlock handle */
-#endif
+    LeaveCriticalSection(&_pioinfo(fh)->lock);
 
     return fh;                 /* return handle */
 }
 
-#define _open_osfhandle my_open_osfhandle
 #endif /* USE_FIXED_OSFHANDLE */
 
 /* simulate flock by locking a range on the file */
@@ -2048,7 +2165,7 @@ DllExport FILE *
 win32_fopen(const char *filename, const char *mode)
 {
     dTHXo;
-    WCHAR wMode[MODE_SIZE], wBuffer[MAX_PATH];
+    WCHAR wMode[MODE_SIZE], wBuffer[MAX_PATH+1];
     FILE *f;
     
     if (!*filename)
@@ -2097,7 +2214,7 @@ DllExport FILE *
 win32_freopen(const char *path, const char *mode, FILE *stream)
 {
     dTHXo;
-    WCHAR wMode[MODE_SIZE], wBuffer[MAX_PATH];
+    WCHAR wMode[MODE_SIZE], wBuffer[MAX_PATH+1];
     if (stricmp(path, "/dev/null")==0)
        path = "NUL";
 
@@ -2283,7 +2400,9 @@ win32_popen(const char *command, const char *mode)
        /* close saved handle */
        win32_close(oldfd);
 
+       LOCK_FDPID_MUTEX;
        sv_setiv(*av_fetch(w32_fdpid, p[parent], TRUE), childpid);
+       UNLOCK_FDPID_MUTEX;
 
        /* set process id so that it can be returned by perl's open() */
        PL_forkprocess = childpid;
@@ -2319,7 +2438,9 @@ win32_pclose(FILE *pf)
     int childpid, status;
     SV *sv;
 
+    LOCK_FDPID_MUTEX;
     sv = *av_fetch(w32_fdpid, win32_fileno(pf), TRUE);
+
     if (SvIOK(sv))
        childpid = SvIVX(sv);
     else
@@ -2332,6 +2453,7 @@ win32_pclose(FILE *pf)
 
     win32_fclose(pf);
     SvIVX(sv) = 0;
+    UNLOCK_FDPID_MUTEX;
 
     if (win32_waitpid(childpid, &status, 0) == -1)
         return -1;
@@ -2403,11 +2525,11 @@ win32_link(const char *oldname, const char *newname)
 {
     dTHXo;
     BOOL (__stdcall *pfnCreateHardLinkW)(LPCWSTR,LPCWSTR,LPSECURITY_ATTRIBUTES);
-    WCHAR wOldName[MAX_PATH];
-    WCHAR wNewName[MAX_PATH];
+    WCHAR wOldName[MAX_PATH+1];
+    WCHAR wNewName[MAX_PATH+1];
 
     if (IsWin95())
-       Perl_die(aTHX_ PL_no_func, "link");
+       Perl_croak(aTHX_ PL_no_func, "link");
 
     pfnCreateHardLinkW =
        (BOOL (__stdcall *)(LPCWSTR, LPCWSTR, LPSECURITY_ATTRIBUTES))
@@ -2429,26 +2551,31 @@ win32_link(const char *oldname, const char *newname)
 DllExport int
 win32_rename(const char *oname, const char *newname)
 {
-    WCHAR wOldName[MAX_PATH];
-    WCHAR wNewName[MAX_PATH];
-    char szOldName[MAX_PATH];
+    WCHAR wOldName[MAX_PATH+1];
+    WCHAR wNewName[MAX_PATH+1];
+    char szOldName[MAX_PATH+1];
+    char szNewName[MAX_PATH+1];
     BOOL bResult;
+    dTHXo;
+
     /* XXX despite what the documentation says about MoveFileEx(),
      * it doesn't work under Windows95!
      */
     if (IsWinNT()) {
-       dTHXo;
+       DWORD dwFlags = MOVEFILE_COPY_ALLOWED;
        if (USING_WIDE()) {
            A2WHELPER(oname, wOldName, sizeof(wOldName));
            A2WHELPER(newname, wNewName, sizeof(wNewName));
+           if (wcsicmp(wNewName, wOldName))
+               dwFlags |= MOVEFILE_REPLACE_EXISTING;
            wcscpy(wOldName, PerlDir_mapW(wOldName));
-           bResult = MoveFileExW(wOldName,PerlDir_mapW(wNewName),
-                       MOVEFILE_COPY_ALLOWED|MOVEFILE_REPLACE_EXISTING);
+           bResult = MoveFileExW(wOldName,PerlDir_mapW(wNewName), dwFlags);
        }
        else {
-           strcpy(szOldName, PerlDir_mapA(szOldName));
-           bResult = MoveFileExA(szOldName,PerlDir_mapA(newname),
-                       MOVEFILE_COPY_ALLOWED|MOVEFILE_REPLACE_EXISTING);
+           if (stricmp(newname, oname))
+               dwFlags |= MOVEFILE_REPLACE_EXISTING;
+           strcpy(szOldName, PerlDir_mapA(oname));
+           bResult = MoveFileExA(szOldName,PerlDir_mapA(newname), dwFlags);
        }
        if (!bResult) {
            DWORD err = GetLastError();
@@ -2473,14 +2600,17 @@ win32_rename(const char *oname, const char *newname)
     }
     else {
        int retval = 0;
-       char tmpname[MAX_PATH+1];
+       char szTmpName[MAX_PATH+1];
        char dname[MAX_PATH+1];
        char *endname = Nullch;
        STRLEN tmplen = 0;
        DWORD from_attr, to_attr;
 
+       strcpy(szOldName, PerlDir_mapA(oname));
+       strcpy(szNewName, PerlDir_mapA(newname));
+
        /* if oname doesn't exist, do nothing */
-       from_attr = GetFileAttributes(oname);
+       from_attr = GetFileAttributes(szOldName);
        if (from_attr == 0xFFFFFFFF) {
            errno = ENOENT;
            return -1;
@@ -2490,7 +2620,7 @@ win32_rename(const char *oname, const char *newname)
         * don't delete it in case oname happens to be the same file
         * (but perhaps accessed via a different path)
         */
-       to_attr = GetFileAttributes(newname);
+       to_attr = GetFileAttributes(szNewName);
        if (to_attr != 0xFFFFFFFF) {
            /* if newname is a directory, we fail
             * XXX could overcome this with yet more convoluted logic */
@@ -2498,29 +2628,29 @@ win32_rename(const char *oname, const char *newname)
                errno = EACCES;
                return -1;
            }
-           tmplen = strlen(newname);
-           strcpy(tmpname,newname);
-           endname = tmpname+tmplen;
-           for (; endname > tmpname ; --endname) {
+           tmplen = strlen(szNewName);
+           strcpy(szTmpName,szNewName);
+           endname = szTmpName+tmplen;
+           for (; endname > szTmpName ; --endname) {
                if (*endname == '/' || *endname == '\\') {
                    *endname = '\0';
                    break;
                }
            }
-           if (endname > tmpname)
-               endname = strcpy(dname,tmpname);
+           if (endname > szTmpName)
+               endname = strcpy(dname,szTmpName);
            else
                endname = ".";
 
            /* get a temporary filename in same directory
             * XXX is this really the best we can do? */
-           if (!GetTempFileName((LPCTSTR)endname, "plr", 0, tmpname)) {
+           if (!GetTempFileName((LPCTSTR)endname, "plr", 0, szTmpName)) {
                errno = ENOENT;
                return -1;
            }
-           DeleteFile(tmpname);
+           DeleteFile(szTmpName);
 
-           retval = rename(newname, tmpname);
+           retval = rename(szNewName, szTmpName);
            if (retval != 0) {
                errno = EACCES;
                return retval;
@@ -2528,16 +2658,16 @@ win32_rename(const char *oname, const char *newname)
        }
 
        /* rename oname to newname */
-       retval = rename(oname, newname);
+       retval = rename(szOldName, szNewName);
 
        /* if we created a temporary file before ... */
        if (endname != Nullch) {
            /* ...and rename succeeded, delete temporary file/directory */
            if (retval == 0)
-               DeleteFile(tmpname);
+               DeleteFile(szTmpName);
            /* else restore it to what it was */
            else
-               (void)rename(tmpname, newname);
+               (void)rename(szTmpName, szNewName);
        }
        return retval;
     }
@@ -2567,7 +2697,7 @@ win32_open(const char *path, int flag, ...)
     dTHXo;
     va_list ap;
     int pmode;
-    WCHAR wBuffer[MAX_PATH];
+    WCHAR wBuffer[MAX_PATH+1];
 
     va_start(ap, flag);
     pmode = va_arg(ap, int);
@@ -2621,44 +2751,8 @@ win32_dup2(int fd1,int fd2)
 #define FTEXT          0x80    /* file handle is in text mode */
 #define MAX_DESCRIPTOR_COUNT   (64*32) /* this is the maximun that MSVCRT can handle */
 
-/*
- * Control structure for lowio file handles
- */
-typedef struct {
-    long osfhnd;    /* underlying OS file HANDLE */
-    char osfile;    /* attributes of file (e.g., open in text mode?) */
-    char pipech;    /* one char buffer for handles opened on pipes */
-    int lockinitflag;
-    CRITICAL_SECTION lock;
-} ioinfo;
-
-
-/*
- * Array of arrays of control structures for lowio files.
- */
-EXTERN_C _CRTIMP ioinfo* __pioinfo[];
-
-/*
- * Definition of IOINFO_L2E, the log base 2 of the number of elements in each
- * array of ioinfo structs.
- */
-#define IOINFO_L2E         5
-
-/*
- * Definition of IOINFO_ARRAY_ELTS, the number of elements in ioinfo array
- */
-#define IOINFO_ARRAY_ELTS   (1 << IOINFO_L2E)
-
-/*
- * Access macros for getting at an ioinfo struct and its fields from a
- * file handle
- */
-#define _pioinfo(i) (__pioinfo[(i) >> IOINFO_L2E] + ((i) & (IOINFO_ARRAY_ELTS - 1)))
-#define _osfhnd(i)  (_pioinfo(i)->osfhnd)
-#define _osfile(i)  (_pioinfo(i)->osfile)
-#define _pipech(i)  (_pioinfo(i)->pipech)
-
-int __cdecl _fixed_read(int fh, void *buf, unsigned cnt)
+int __cdecl
+_fixed_read(int fh, void *buf, unsigned cnt)
 {
     int bytes_read;                 /* number of bytes read */
     char *buffer;                   /* buffer to read to */
@@ -2678,7 +2772,12 @@ int __cdecl _fixed_read(int fh, void *buf, unsigned cnt)
        return -1;
     }
 
-    EnterCriticalSection(&(_pioinfo(fh)->lock));  /* lock file */
+    /*
+     * If lockinitflag is FALSE, assume fd is device
+     * lockinitflag is set to TRUE by open.
+     */
+    if (_pioinfo(fh)->lockinitflag)
+       EnterCriticalSection(&(_pioinfo(fh)->lock));  /* lock file */
 
     bytes_read = 0;                 /* nothing read yet */
     buffer = (char*)buf;
@@ -2826,7 +2925,8 @@ int __cdecl _fixed_read(int fh, void *buf, unsigned cnt)
     }
 
 functionexit:  
-    LeaveCriticalSection(&(_pioinfo(fh)->lock));    /* unlock file */
+    if (_pioinfo(fh)->lockinitflag)
+       LeaveCriticalSection(&(_pioinfo(fh)->lock));    /* unlock file */
 
     return bytes_read;
 }
@@ -2854,7 +2954,7 @@ win32_mkdir(const char *dir, int mode)
 {
     dTHXo;
     if (USING_WIDE()) {
-       WCHAR wBuffer[MAX_PATH];
+       WCHAR wBuffer[MAX_PATH+1];
        A2WHELPER(dir, wBuffer, sizeof(wBuffer));
        return _wmkdir(PerlDir_mapW(wBuffer));
     }
@@ -2866,7 +2966,7 @@ win32_rmdir(const char *dir)
 {
     dTHXo;
     if (USING_WIDE()) {
-       WCHAR wBuffer[MAX_PATH];
+       WCHAR wBuffer[MAX_PATH+1];
        A2WHELPER(dir, wBuffer, sizeof(wBuffer));
        return _wrmdir(PerlDir_mapW(wBuffer));
     }
@@ -2878,7 +2978,7 @@ win32_chdir(const char *dir)
 {
     dTHXo;
     if (USING_WIDE()) {
-       WCHAR wBuffer[MAX_PATH];
+       WCHAR wBuffer[MAX_PATH+1];
        A2WHELPER(dir, wBuffer, sizeof(wBuffer));
        return _wchdir(wBuffer);
     }
@@ -2890,7 +2990,7 @@ win32_access(const char *path, int mode)
 {
     dTHXo;
     if (USING_WIDE()) {
-       WCHAR wBuffer[MAX_PATH];
+       WCHAR wBuffer[MAX_PATH+1];
        A2WHELPER(path, wBuffer, sizeof(wBuffer));
        return _waccess(PerlDir_mapW(wBuffer), mode);
     }
@@ -2902,7 +3002,7 @@ win32_chmod(const char *path, int mode)
 {
     dTHXo;
     if (USING_WIDE()) {
-       WCHAR wBuffer[MAX_PATH];
+       WCHAR wBuffer[MAX_PATH+1];
        A2WHELPER(path, wBuffer, sizeof(wBuffer));
        return _wchmod(PerlDir_mapW(wBuffer), mode);
     }
@@ -3088,6 +3188,7 @@ win32_spawnvp(int mode, const char *cmdname, const char *const *argv)
     int ret;
     void* env;
     char* dir;
+    child_IO_table tbl;
     STARTUPINFO StartupInfo;
     PROCESS_INFORMATION ProcessInformation;
     DWORD create = 0;
@@ -3116,9 +3217,20 @@ win32_spawnvp(int mode, const char *cmdname, const char *const *argv)
     }
     memset(&StartupInfo,0,sizeof(StartupInfo));
     StartupInfo.cb = sizeof(StartupInfo);
-    StartupInfo.hStdInput  = GetStdHandle(STD_INPUT_HANDLE);
-    StartupInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
-    StartupInfo.hStdError  = GetStdHandle(STD_ERROR_HANDLE);
+    memset(&tbl,0,sizeof(tbl));
+    PerlEnv_get_child_IO(&tbl);
+    StartupInfo.dwFlags                = tbl.dwFlags;
+    StartupInfo.dwX            = tbl.dwX; 
+    StartupInfo.dwY            = tbl.dwY; 
+    StartupInfo.dwXSize                = tbl.dwXSize; 
+    StartupInfo.dwYSize                = tbl.dwYSize; 
+    StartupInfo.dwXCountChars  = tbl.dwXCountChars; 
+    StartupInfo.dwYCountChars  = tbl.dwYCountChars; 
+    StartupInfo.dwFillAttribute        = tbl.dwFillAttribute; 
+    StartupInfo.wShowWindow    = tbl.wShowWindow; 
+    StartupInfo.hStdInput      = tbl.childStdIn;
+    StartupInfo.hStdOutput     = tbl.childStdOut;
+    StartupInfo.hStdError      = tbl.childStdErr;
     if (StartupInfo.hStdInput != INVALID_HANDLE_VALUE &&
        StartupInfo.hStdOutput != INVALID_HANDLE_VALUE &&
        StartupInfo.hStdError != INVALID_HANDLE_VALUE)
@@ -3390,6 +3502,10 @@ win32_free(void *block)
 int
 win32_open_osfhandle(long handle, int flags)
 {
+#ifdef USE_FIXED_OSFHANDLE
+    if (IsWin95())
+       return my_open_osfhandle(handle, flags);
+#endif
     return _open_osfhandle(handle, flags);
 }
 
@@ -3405,7 +3521,7 @@ win32_dynaload(const char* filename)
     dTHXo;
     HMODULE hModule;
     if (USING_WIDE()) {
-       WCHAR wfilename[MAX_PATH];
+       WCHAR wfilename[MAX_PATH+1];
        A2WHELPER(filename, wfilename, sizeof(wfilename));
        hModule = LoadLibraryExW(PerlDir_mapW(wfilename), NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
     }
@@ -3839,15 +3955,15 @@ XS(w32_CopyFile)
     if (items != 3)
        Perl_croak(aTHX_ "usage: Win32::CopyFile($from, $to, $overwrite)");
     if (USING_WIDE()) {
-       WCHAR wSourceFile[MAX_PATH];
-       WCHAR wDestFile[MAX_PATH];
+       WCHAR wSourceFile[MAX_PATH+1];
+       WCHAR wDestFile[MAX_PATH+1];
        A2WHELPER(SvPV_nolen(ST(0)), wSourceFile, sizeof(wSourceFile));
        wcscpy(wSourceFile, PerlDir_mapW(wSourceFile));
        A2WHELPER(SvPV_nolen(ST(1)), wDestFile, sizeof(wDestFile));
        bResult = CopyFileW(wSourceFile, PerlDir_mapW(wDestFile), !SvTRUE(ST(2)));
     }
     else {
-       char szSourceFile[MAX_PATH];
+       char szSourceFile[MAX_PATH+1];
        strcpy(szSourceFile, PerlDir_mapA(SvPV_nolen(ST(0))));
        bResult = CopyFileA(szSourceFile, PerlDir_mapA(SvPV_nolen(ST(1))), !SvTRUE(ST(2)));
     }
@@ -3864,18 +3980,6 @@ Perl_init_os_extras(void)
     char *file = __FILE__;
     dXSUB_SYS;
 
-    w32_perlshell_tokens = Nullch;
-    w32_perlshell_items = -1;
-    w32_fdpid = newAV();               /* XXX needs to be in Perl_win32_init()? */
-    New(1313, w32_children, 1, child_tab);
-    w32_num_children = 0;
-    w32_init_socktype = 0;
-#ifdef USE_ITHREADS
-    w32_pseudo_id = 0;
-    New(1313, w32_pseudo_children, 1, child_tab);
-    w32_num_pseudo_children = 0;
-#endif
-
     /* these names are Activeware compatible */
     newXS("Win32::GetCwd", w32_GetCwd, file);
     newXS("Win32::SetCwd", w32_SetCwd, file);
@@ -3925,15 +4029,58 @@ Perl_win32_init(int *argcp, char ***argvp)
     MALLOC_INIT;
 }
 
-#ifdef USE_ITHREADS
+void
+win32_get_child_IO(child_IO_table* ptbl)
+{
+    ptbl->childStdIn   = GetStdHandle(STD_INPUT_HANDLE);
+    ptbl->childStdOut  = GetStdHandle(STD_OUTPUT_HANDLE);
+    ptbl->childStdErr  = GetStdHandle(STD_ERROR_HANDLE);
+}
+
+#ifdef HAVE_INTERP_INTERN
 
 #  ifdef PERL_OBJECT
+#    undef Perl_sys_intern_init
+#    define Perl_sys_intern_init CPerlObj::Perl_sys_intern_init
 #    undef Perl_sys_intern_dup
 #    define Perl_sys_intern_dup CPerlObj::Perl_sys_intern_dup
+#    undef Perl_sys_intern_clear
+#    define Perl_sys_intern_clear CPerlObj::Perl_sys_intern_clear
 #    define pPerl this
 #  endif
 
 void
+Perl_sys_intern_init(pTHX)
+{
+    w32_perlshell_tokens       = Nullch;
+    w32_perlshell_vec          = (char**)NULL;
+    w32_perlshell_items                = 0;
+    w32_fdpid                  = newAV();
+    New(1313, w32_children, 1, child_tab);
+    w32_num_children           = 0;
+#  ifdef USE_ITHREADS
+    w32_pseudo_id              = 0;
+    New(1313, w32_pseudo_children, 1, child_tab);
+    w32_num_pseudo_children    = 0;
+#  endif
+    w32_init_socktype          = 0;
+}
+
+void
+Perl_sys_intern_clear(pTHX)
+{
+    Safefree(w32_perlshell_tokens);
+    Safefree(w32_perlshell_vec);
+    /* NOTE: w32_fdpid is freed by sv_clean_all() */
+    Safefree(w32_children);
+#  ifdef USE_ITHREADS
+    Safefree(w32_pseudo_children);
+#  endif
+}
+
+#  ifdef USE_ITHREADS
+
+void
 Perl_sys_intern_dup(pTHX_ struct interp_intern *src, struct interp_intern *dst)
 {
     dst->perlshell_tokens      = Nullch;
@@ -3941,10 +4088,44 @@ Perl_sys_intern_dup(pTHX_ struct interp_intern *src, struct interp_intern *dst)
     dst->perlshell_items       = 0;
     dst->fdpid                 = newAV();
     Newz(1313, dst->children, 1, child_tab);
-    Newz(1313, dst->pseudo_children, 1, child_tab);
     dst->pseudo_id             = 0;
-    dst->children->num         = 0;
+    Newz(1313, dst->pseudo_children, 1, child_tab);
     dst->thr_intern.Winit_socktype = src->thr_intern.Winit_socktype;
 }
+#  endif /* USE_ITHREADS */
+#endif /* HAVE_INTERP_INTERN */
+
+#ifdef PERL_OBJECT
+#  undef this
+#  define this pPerl
 #endif
 
+static void
+win32_free_argvw(pTHXo_ void *ptr)
+{
+    char** argv = (char**)ptr;
+    while(*argv) {
+       Safefree(*argv);
+       *argv++ = Nullch;
+    }
+}
+
+void
+win32_argv2utf8(int argc, char** argv)
+{
+    dTHXo;
+    char* psz;
+    int length, wargc;
+    LPWSTR* lpwStr = CommandLineToArgvW(GetCommandLineW(), &wargc);
+    if (lpwStr && argc) {
+       while (argc--) {
+           length = WideCharToMultiByte(CP_UTF8, 0, lpwStr[--wargc], -1, NULL, 0, NULL, NULL);
+           Newz(0, psz, length, char);
+           WideCharToMultiByte(CP_UTF8, 0, lpwStr[wargc], -1, psz, length, NULL, NULL);
+           argv[argc] = psz;
+       }
+       call_atexit(win32_free_argvw, argv);
+    }
+    GlobalFree((HGLOBAL)lpwStr);
+}
+