diff --git a/lib/modules/Stdio.pmod/module.pmod b/lib/modules/Stdio.pmod/module.pmod
index bc11871eb185e6ea56d8100f133f10a58aee7dfc..ac53dab4a60d7c15aeb32011af351174ee82da27 100644
--- a/lib/modules/Stdio.pmod/module.pmod
+++ b/lib/modules/Stdio.pmod/module.pmod
@@ -744,6 +744,8 @@ class File
   //!     @value PROP_SEND_FD
   //!       The resulting pipe might support sending of file descriptors
   //!       (see @[send_fd()] and @[receive_fd()] for details).
+  //!     @value PROP_TTY
+  //!       The resulting pipe is a pseudo-tty.
   //!     @value PROP_REVERSE
   //!       The resulting pipe supports communication "backwards" (but
   //!       not necessarily "forwards", see @[PROP_BIDIRECTIONAL]).
@@ -757,6 +759,9 @@ class File
   //!
   //! The two ends of a bi-directional pipe are indistinguishable.
   //!
+  //! For @[PROP_TTY] the returned object is the slave (unless
+  //! @[PROP_REVERSE] has been specified).
+  //!
   //! If the File object this function is called in was open to begin with,
   //! it will be closed before the pipe is created.
   //!
@@ -768,7 +773,7 @@ class File
   //!   @[Process.create_process()], @[send_fd()], @[receive_fd()],
   //!   @[PROP_IPC], @[PROP_NONBLOCK], @[PROP_SEND_FD],
   //!   @[PROP_SHUTDOWN], @[PROP_BUFFERED], @[PROP_REVERSE],
-  //!   @[PROP_BIDIRECTIONAL]
+  //!   @[PROP_BIDIRECTIONAL], @[PROP_TTY]
   //!
   File pipe(void|int required_properties)
   {
diff --git a/src/configure.in b/src/configure.in
index 854ca89a243e9d86cf2e8b90b5f2f78ca36446a1..dd0f0dfa9bb0e506c00888733fa10ed54355c1e1 100644
--- a/src/configure.in
+++ b/src/configure.in
@@ -3312,6 +3312,67 @@ AC_CHECK_HEADERS(winsock2.h sys/rusage.h time.h sys/time.h sys/types.h \
 #endif
 ])
 
+AC_CHECK_TYPES([HPCON, LPPROC_THREAD_ATTRIBUTE_LIST, LPSTARTUPINFOEXW],,,[
+#if (defined(__WINNT__) || defined(__WIN32__)) && !defined(__NT__)
+#define __NT__
+#endif
+#ifndef _LARGEFILE_SOURCE
+#  define _FILE_OFFSET_BITS 64
+#  define _LARGEFILE_SOURCE
+#endif
+#ifndef __STDC_EXT__
+#  define __STDC_EXT__
+#endif /* !__STDC_EXT__ */
+#ifndef _PROTOTYPES
+#  define _PROTOTYPES
+#endif /* !_PROTOTYPES */
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif /* !_GNU_SOURCE */
+#ifdef __NT__
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN
+#endif
+#ifndef WIN32
+#define WIN32   100     /* WinNT 1.0 */
+#endif
+#if !defined(_WIN32_WINDOWS) || (_WIN32_WINDOWS < 0x500)
+#undef _WIN32_WINDOWS
+#define _WIN32_WINDOWS 0x0500
+#endif
+#if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x500)
+#undef _WIN32_WINNT
+#define _WIN32_WINNT 0x0500
+#endif
+#if !defined(NTDDI_VERSION) || (NTDDI_VERSION < 0x05000000)
+#undef NTDDI_VERSION
+#define NTDDI_VERSION 0x05000000
+#endif
+#endif /* __NT__ */
+#ifdef __amigaos__
+#define __USE_NETINET_IN_H
+#endif
+#ifndef __BUILTIN_VA_ARG_INCR
+#define __BUILTIN_VA_ARG_INCR   1
+#endif /* !__BUILTIN_VA_ARG_INCR */
+#ifdef HAVE_WINDOWS_H
+#include <windows.h>
+#undef HAVE_WINDOWS_H
+#endif
+/* Necessary to find sys/socket.h on MacOS X 10.3 */
+#if HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+/* Necessary to find ws2tcpip.h on WIN32. */
+#ifdef HAVE_WINSOCK2_H
+# include <winsock2.h>
+#endif
+/* Necessary to find sys/user.h on OpenBSD */
+#ifdef HAVE_SYS_PARAM_H
+# include <sys/param.h>
+#endif
+])
+
 # Setjmp.
 #
 # POSIX defines sigsetjmp().
diff --git a/src/fdlib.c b/src/fdlib.c
index 5cd2c3f1a81a50e74193422624d7f79af2fd4435..d25465ca4ee5dcc502b7d359ad0de256f016722e 100644
--- a/src/fdlib.c
+++ b/src/fdlib.c
@@ -906,7 +906,7 @@ static int IsUncRoot(const p_wchar1 *path)
   return 0 ;
 }
 
-PMOD_EXPORT p_wchar1 *pike_dwim_utf8_to_utf16(const p_wchar0 *str)
+p_wchar1 *low_dwim_utf8_to_utf16(const p_wchar0 *str, size_t len)
 {
   /* NB: Maximum expansion factor is 2.
    *
@@ -919,7 +919,6 @@ PMOD_EXPORT p_wchar1 *pike_dwim_utf8_to_utf16(const p_wchar0 *str)
    * NB: Some extra padding at the end for NUL and adding
    *     of terminating slashes, etc.
    */
-  size_t len = strlen(str);
   p_wchar1 *res = malloc((len + 4) * sizeof(p_wchar1));
   size_t i = 0, j = 0;
 
@@ -979,6 +978,11 @@ PMOD_EXPORT p_wchar1 *pike_dwim_utf8_to_utf16(const p_wchar0 *str)
   return res;
 }
 
+PMOD_EXPORT p_wchar1 *pike_dwim_utf8_to_utf16(const p_wchar0 *str)
+{
+  return low_dwim_utf8_to_utf16(str, strlen(str));
+}
+
 PMOD_EXPORT p_wchar0 *pike_utf16_to_utf8(const p_wchar1 *str)
 {
   /* NB: Maximum expansion factor is 1.5.
diff --git a/src/fdlib.h b/src/fdlib.h
index 1e1bd98333dd45fce1a1cd5f3d74968b8848ec4d..39a1a2901706b522dc7c4d51e42fd3d6cb6d4d26 100644
--- a/src/fdlib.h
+++ b/src/fdlib.h
@@ -45,6 +45,7 @@
 #define fd_BIDIRECTIONAL     16
 #define fd_REVERSE	     32
 #define fd_SEND_FD           64
+#define fd_TTY		    128
 
 
 #if defined(HAVE_WINSOCK_H)
@@ -55,6 +56,7 @@
 #define FILE_CAPABILITIES (fd_INTERPROCESSABLE)
 #define PIPE_CAPABILITIES (fd_INTERPROCESSABLE | fd_BUFFERED)
 #define SOCKET_CAPABILITIES (fd_BIDIRECTIONAL | fd_CAN_NONBLOCK | fd_CAN_SHUTDOWN)
+#define TTY_CAPABILITIES (fd_TTY | fd_INTERPROCESSABLE | fd_BIDIRECTIONAL | fd_CAN_NONBLOCK)
 
 #include <winbase.h>
 
@@ -70,6 +72,43 @@ typedef off_t PIKE_OFF_T;
 #define PRINTPIKEOFFT PRINTOFFT
 #endif
 
+/*
+ * Some macros, structures and typedefs that are needed for ConPTY.
+ */
+#ifndef HAVE_HPCON
+typedef VOID* HPCON;
+#endif
+#ifndef EXTENDED_STARTUPINFO_PRESENT
+#define EXTENDED_STARTUPINFO_PRESENT 0x00080000
+#endif
+#ifndef PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE
+#define PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE 0x00020016
+#endif
+#ifndef HAVE_LPPROC_THREAD_ATTRIBUTE_LIST
+typedef struct _PROC_THREAD_ATTRIBUTE_ENTRY
+{
+  DWORD_PTR	Attribute;
+  SIZE_T	cbSize;
+  PVOID		lpValue;
+} PROC_THREAD_ATTRIBUTE_ENTRY, *LPPROC_THREAD_ATTRIBUTE_ENTRY;
+typedef struct _PROC_THREAD_ATTRIBUTE_LIST
+{
+  DWORD			dwFlags;
+  ULONG			Size;
+  ULONG			Count;
+  ULONG			Reserved;
+  PULONG		Unknown;
+  PROC_THREAD_ATTRIBUTE_ENTRY	Entries[ANYSIZE_ARRAY];
+} PROC_THREAD_ATTRIBUTE_LIST, *LPPROC_THREAD_ATTRIBUTE_LIST;
+#endif
+#ifndef HAVE_LPSTARTUPINFOEXW
+typedef struct _STARTUPINFOEXW
+{
+  STARTUPINFOW StartupInfo;
+  LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList;
+} STARTUPINFOEXW, *LPSTARTUPINFOEXW;
+#endif
+
 #define SOCKFUN1(NAME,T1) PMOD_EXPORT int PIKE_CONCAT(debug_fd_,NAME) (FD,T1);
 #define SOCKFUN2(NAME,T1,T2) PMOD_EXPORT int PIKE_CONCAT(debug_fd_,NAME) (FD,T1,T2);
 #define SOCKFUN3(NAME,T1,T2,T3) PMOD_EXPORT int PIKE_CONCAT(debug_fd_,NAME) (FD,T1,T2,T3);
@@ -130,6 +169,7 @@ PMOD_EXPORT char *debug_fd_info(int fd);
 PMOD_EXPORT int debug_fd_query_properties(int fd, int guess);
 void fd_init(void);
 void fd_exit(void);
+p_wchar1 *low_dwim_utf8_to_utf16(const p_wchar0 *str, size_t len);
 PMOD_EXPORT p_wchar1 *pike_dwim_utf8_to_utf16(const p_wchar0 *str);
 PMOD_EXPORT p_wchar0 *pike_utf16_to_utf8(const p_wchar1 *str);
 PMOD_EXPORT int debug_fd_stat(const char *file, PIKE_STAT_T *buf);
@@ -538,6 +578,7 @@ typedef struct my_fd_set_s my_fd_set;
 #endif
 #define UNIX_SOCKET_CAPABILITIES (fd_INTERPROCESSABLE | fd_BIDIRECTIONAL | fd_CAN_NONBLOCK | fd_SEND_FD)
 #define SOCKET_CAPABILITIES (fd_INTERPROCESSABLE | fd_BIDIRECTIONAL | fd_CAN_NONBLOCK | fd_CAN_SHUTDOWN)
+#define TTY_CAPABILITIES (fd_TTY | fd_INTERPROCESSABLE | fd_BIDIRECTIONAL | fd_CAN_NONBLOCK)
 
 #endif /* Don't HAVE_WINSOCK */
 
diff --git a/src/modules/_Stdio/configure.in b/src/modules/_Stdio/configure.in
index 14339740596987846ab6540029af7458a7520abd..e81c1f75be09afbe2282dba143017e02209a551f 100644
--- a/src/modules/_Stdio/configure.in
+++ b/src/modules/_Stdio/configure.in
@@ -5,14 +5,14 @@ AC_MODULE_INIT()
 
 AC_DEFINE(WITH_TERMIOS)
 
-AC_HAVE_HEADERS(sys/types.h sys/socket.h arpa/inet.h sys/socketvar.h \
+AC_HAVE_HEADERS(sys/types.h sys/socket.h arpa/inet.h sys/socketvar.h pty.h \
   netinet/in.h poll.h sys/poll.h sys/uio.h sys/mman.h linux/mman.h sys/time.h \
   sys/param.h sys/mount.h ustat.h sys/statfs.h sys/statvfs.h sys/vfs.h \
   sys/stream.h sys/protosw.h netdb.h sys/sysproto.h winsock2.h ws2tcpip.h \
   direct.h sys/wait.h process.h sys/file.h net/netdb.h limits.h unistd.h \
   termios.h poll.h sys/poll.h sys/select.h sys/un.h netinet/tcp.h \
   sys/sendfile.h sys/ioctl.h linux/if.h sys/xattr.h libzfs.h io.h \
-  AvailabilityMacros.h,,,[
+  AvailabilityMacros.h sys/stropts.h,,,[
 /* Needed for <sys/socket.h> on FreeBSD 4.9. */
 #ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
@@ -68,6 +68,7 @@ AC_CHECK_LIB(gmp, main)
 
 AC_HAVE_FUNCS(readdir_r statvfs statfs ustat lseek64 lstat fsync \
  grantpt unlockpt ptsname posix_openpt socketpair writev sendfile munmap \
+ openpty \
  madvise poll setsockopt getprotobyname inet_ntoa \
  inet_ntop execve listxattr flistxattr getxattr fgetxattr setxattr fsetxattr \
  fdopendir pathconf fpathconf dirfd fstatat openat unlinkat kqueue access)
diff --git a/src/modules/_Stdio/file.c b/src/modules/_Stdio/file.c
index 75de17c9d96ff13950f4bd3735303921133a2a11..551ff6bfb940452f99c5bc1ce988cb5d706b61c8 100644
--- a/src/modules/_Stdio/file.c
+++ b/src/modules/_Stdio/file.c
@@ -62,6 +62,21 @@
 #include <sys/ioctl.h>
 #endif
 
+#ifdef HAVE_SYS_STROPTS_H
+#include <sys/stropts.h>
+#endif
+
+#ifdef HAVE_PTY_H
+#include <pty.h>
+#endif
+
+#ifdef HAVE_TERMIOS_H
+#include <termios.h>
+#elif defined(HAVE_SYS_TERMIOS_H)
+/* NB: Deprecated by <termios.h> above. */
+#include <sys/termios.h>
+#endif
+
 #ifdef HAVE_LINUX_IF_H
 #include <linux/if.h>
 #endif
@@ -2507,23 +2522,19 @@ static int do_close(int flags)
   }
 }
 
-/*! @decl string grantpt()
- *!
- *!  If this file has been created by calling @[openpt()], return the
- *!  filename of the associated pts-file. This function should only be
- *!  called once.
- *!
- *! @returns
- *!   Returns the filename of the corresponding pts.
- *!
- *!  @note
- *!    This function is only available on some platforms.
- */
-#if defined(HAVE_GRANTPT) || defined(USE_PT_CHMOD) || defined(USE_CHGPT)
-static void file_grantpt( INT32 args )
+#if !defined(HAVE_POSIX_OPENPT) && defined(PTY_MASTER_PATHNAME)
+static int my_posix_openpt(int flags)
 {
-  pop_n_elems(args);
+  return open(PTY_MASTER_PATHNAME, flags);
+}
+#define HAVE_POSIX_OPENPT
+#define posix_openpt(FLAGS)	my_posix_openpt(FLAGS)
+#endif
+
+#ifndef HAVE_GRANTPT
 #if defined(USE_PT_CHMOD) || defined(USE_CHGPT)
+static int my_grantpt(int m)
+{
   push_text("Process.Process");
   APPLY_MASTER("resolv", 1);
 
@@ -2553,16 +2564,76 @@ static void file_grantpt( INT32 args )
   apply_svalue(Pike_sp-3, 2);
   apply(Pike_sp[-1].u.object, "wait", 0);
   if(!UNSAFE_IS_ZERO(Pike_sp-1)) {
-    Pike_error(
-#ifdef USE_PT_CHMOD
-	       USE_PT_CHMOD
-#else /* USE_CHGPT */
-	       USE_CHGPT
-#endif /* USE_PT_CHMOD */
-	       " returned error %d.\n", Pike_sp[-1].u.integer);
+    errno = EINVAL;
+    return -1;
   }
-  pop_n_elems(3);
-#else /* HAVE_GRANTPT */
+  return 0;
+}
+#define HAVE_GRANTPT
+#define grantpt(M)	my_grantpt(M)
+#endif
+#endif
+
+#ifndef HAVE_UNLOCKPT
+#define HAVE_UNLOCKPT
+#define unlockpt(m)	0
+#endif
+
+#if !defined(HAVE_OPENPTY) && defined(HAVE_PTSNAME) && defined(HAVE_POSIX_OPENPT)
+static int my_openpty(int *master, int *slave, void *ignored_name,
+		      void *ignored_termp, void *ignored_winp)
+{
+  int m;
+  int s;
+  char *sname;
+  if (!master || !slave) {
+    errno = EINVAL;
+    return -1;
+  }
+  m = posix_openpt(O_RDWR | O_NOCTTY);
+  if (m < 0) return -1;
+  if (!grantpt(m) && !unlockpt(m) && (sname = ptsname(m))) {
+    int s = open(sname, O_RDWR | O_NOCTTY);
+    if (s >= 0) {
+      *master = m;
+      *slave = s;
+#ifdef I_PUSH
+      /* Push required STREAMS modules.
+       * cf pts(4D)/pts(7D) on Solaris.
+       *
+       * Not required on Solaris 11.4 and later.
+       */
+      ioctl(s, I_PUSH, "ptem");		/* Pseudo terminal emulation mode */
+      ioctl(s, I_PUSH, "ldterm");	/* Terminal line discipline */
+      ioctl(s, I_PUSH, "ttcompat");	/* BSD terminal compatibility */
+#endif
+      return 0;
+    }
+  }
+  close(m);
+  return -1;
+}
+#define HAVE_OPENPTY
+#define openpty(M, S, N, T, W)	my_openpty(M, S, N, T, W)
+#endif
+
+/*! @decl string grantpt()
+ *!
+ *!  If this file has been created by calling @[openpt()], return the
+ *!  filename of the associated pts-file. This function should only be
+ *!  called once.
+ *!
+ *! @returns
+ *!   Returns the filename of the corresponding pts.
+ *!
+ *!  @note
+ *!    This function is only available on some platforms.
+ */
+#if defined(HAVE_GRANTPT)
+static void file_grantpt( INT32 args )
+{
+  pop_n_elems(args);
+
   /* Make sure the fd doesn't get closed when it gets sent
    * to the subprocess (aka /usr/lib/pt_chmod).
    */
@@ -2570,14 +2641,13 @@ static void file_grantpt( INT32 args )
   if( grantpt( FD ) )
     Pike_error("grantpt failed: %s\n", strerror(errno));
   set_close_on_exec(FD, 1);
-#endif /* USE_PT_CHMOD || USE_CHGPT */
+
   push_text( ptsname( FD ) );
-#ifdef HAVE_UNLOCKPT
+
   if( unlockpt( FD ) )
     Pike_error("unlockpt failed: %s\n", strerror(errno));
-#endif
 }
-#endif /* HAVE_GRANTPT || USE_PT_CHMOD || USE_CHGPT */
+#endif /* HAVE_GRANTPT */
 
 /*! @decl int close()
  *! @decl int close(string direction)
@@ -2978,7 +3048,7 @@ static void file_openat(INT32 args)
 }
 #endif /* HAVE_OPENAT */
 
-#if !defined(__NT__) && (defined(HAVE_POSIX_OPENPT) || defined(PTY_MASTER_PATHNAME))
+#if !defined(__NT__) && defined(HAVE_POSIX_OPENPT)
 /*! @decl int openpt(string mode)
  *!
  *! Open the master end of a pseudo-terminal pair.
@@ -2992,9 +3062,8 @@ static void file_openat(INT32 args)
 static void file_openpt(INT32 args)
 {
   int flags,fd;
-#ifdef HAVE_POSIX_OPENPT
   struct pike_string *flag_str;
-#endif
+
   close_fd();
 
   if(args < 1)
@@ -3003,7 +3072,6 @@ static void file_openpt(INT32 args)
   if(TYPEOF(Pike_sp[-args]) != PIKE_T_STRING)
     SIMPLE_BAD_ARG_ERROR("openpt", 1, "string");
 
-#ifdef HAVE_POSIX_OPENPT
   flags = parse((flag_str = Pike_sp[-args].u.string)->str);
   
   if(!( flags &  (FILE_READ | FILE_WRITE)))
@@ -3035,13 +3103,6 @@ static void file_openpt(INT32 args)
   }
   pop_n_elems(args);
   push_int(fd>=0);
-#else
-  if(args > 1)
-    pop_n_elems(args - 1);
-  push_text(PTY_MASTER_PATHNAME);
-  stack_swap();
-  file_open(2);
-#endif
 }
 #endif
 
@@ -4560,6 +4621,17 @@ static void file_pipe(INT32 args)
     }
 #endif
 
+#ifdef HAVE_OPENPTY
+    if (!(type & ~(TTY_CAPABILITIES)))
+    {
+      i = openpty(inout, inout + 1, NULL, NULL, NULL);
+      if (i >= 0) {
+	type = TTY_CAPABILITIES;
+	break;
+      }
+    }
+#endif
+
     if (!i) {
       Pike_error("Cannot create a pipe matching those parameters.\n");
     }
@@ -5920,6 +5992,14 @@ static void f_get_all_active_fd(INT32 args)
  */
 
 
+/*! @decl constant PROP_TTY = 128
+ *!
+ *!   The @[Stdio.File] object supports tty operations.
+ *!
+ *! @seealso
+ *!   @[Stdio.File()->pipe()]
+ */
+
 /*! @decl constant PROP_SEND_FD = 64
  *!
  *!   The @[Stdio.File] object might support the @[Stdio.File()->send_fd()]
@@ -6221,10 +6301,6 @@ static void f_gethostip(INT32 args) {
   push_mapping(m);
 }
 
-#ifdef HAVE_OPENPTY
-#include <pty.h>
-#endif
-
 int fd_write_identifier_offset;
 
 PIKE_MODULE_INIT
@@ -6343,6 +6419,9 @@ PIKE_MODULE_INIT
   add_integer_constant("PROP_BUFFERED",fd_BUFFERED,0);
   add_integer_constant("PROP_BIDIRECTIONAL",fd_BIDIRECTIONAL,0);
   add_integer_constant("PROP_REVERSE",fd_REVERSE,0);
+#ifdef HAVE_OPENPTY
+  add_integer_constant("PROP_TTY",fd_TTY,0);
+#endif
 
   add_integer_constant("PROP_IS_NONBLOCKING", FILE_NONBLOCKING, 0);
 
diff --git a/src/ntlibfuncs.h b/src/ntlibfuncs.h
index ce34a5353344e7cfeda437e39a93994851b356fe..101764dcead7ebceb786fc163b80d4ecbddd8129 100644
--- a/src/ntlibfuncs.h
+++ b/src/ntlibfuncs.h
@@ -21,4 +21,46 @@ NTLIBFUNC(kernel32, BOOL, MoveFileExW, (
   DWORD dwFlags                /* move options  */
 ));
 
+/* The following are needed for pty handling,
+ * and taken from <consoleapi.h> and <processthreadsapi.h>.
+ */
+
+NTLIBFUNC(kernel32, HRESULT, CreatePseudoConsole, (
+  COORD size,
+  HANDLE hInput,
+  HANDLE hOutput,
+  DWORD dwFlags,
+  HPCON *phPC
+));
+
+NTLIBFUNC(kernel32, HRESULT, ResizePseudoConsole, (
+  HPCON hPC,
+  COORD size
+));
+
+NTLIBFUNC(kernel32, VOID, ClosePseudoConsole, (
+  HPCON hPC
+));
+
+NTLIBFUNC(kernel32, BOOL, InitializeProcThreadAttributeList, (
+  LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList,
+  DWORD dwAttributeCount,
+  DWORD dwFlags,
+  PSIZE_T lpSize
+));
+
+NTLIBFUNC(kernel32, VOID, DeleteProcThreadAttributeList, (
+  LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList
+));
+
+NTLIBFUNC(kernel32, BOOL, UpdateProcThreadAttribute, (
+  LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList,
+  DWORD dwFlags,
+  DWORD_PTR Attribute,
+  PVOID lpValue,
+  SIZE_T cbSize,
+  PVOID lpPreviousValue,
+  PSIZE_T lpReturnSize
+));
+
 #endif /* __NT__ */
diff --git a/src/signal_handler.c b/src/signal_handler.c
index c8e3745ebab2d1e84d7c8310b92497051508c3e7..22db1e1356a57e5f0a1c8e39c94e71152d63e2c6 100644
--- a/src/signal_handler.c
+++ b/src/signal_handler.c
@@ -2847,11 +2847,11 @@ void f_create_process(INT32 args)
     HANDLE t1 = DO_NOT_WARN(INVALID_HANDLE_VALUE);
     HANDLE t2 = DO_NOT_WARN(INVALID_HANDLE_VALUE);
     HANDLE t3 = DO_NOT_WARN(INVALID_HANDLE_VALUE);
-    STARTUPINFO info;
+    STARTUPINFOW info;
     PROCESS_INFORMATION proc;
     int ret,err;
-    TCHAR *filename=NULL, *command_line=NULL, *dir=NULL;
-    void *env=NULL;
+    WCHAR *filename=NULL, *command_line=NULL, *dir=NULL;
+    WCHAR *env=NULL;
 
     /* Quote command to allow all characters (if possible) */
     /* Damn! NT doesn't have quoting! The below code attempts to
@@ -2943,7 +2943,8 @@ void f_create_process(INT32 args)
        *       operations on it.
        */
 
-      command_line=(TCHAR *)buf.s.str;
+      command_line = pike_dwim_utf8_to_utf16(buf.s.str);
+      toss_buffer(&buf);
     }
 
     /* FIXME: Ought to set filename properly.
@@ -2951,8 +2952,8 @@ void f_create_process(INT32 args)
 
     memset(&info,0,sizeof(info));
     info.cb=sizeof(info);
-    
-    GetStartupInfo(&info);
+
+    GetStartupInfoW(&info);
 
     /* Protect inherit status for handles */
     LOCK_IMUTEX(&handle_protection_mutex);
@@ -2971,7 +2972,7 @@ void f_create_process(INT32 args)
       {
 	if(TYPEOF(*tmp) == T_STRING)
 	{
-	  dir=(TCHAR *)STR0(tmp->u.string);
+	  dir = pike_dwim_utf8_to_utf16(STR0(tmp->u.string));
 	  /* fprintf(stderr,"DIR: %s\n",STR0(tmp->u.string)); */
 	}
       }
@@ -3020,8 +3021,13 @@ void f_create_process(INT32 args)
 	    f_aggregate(ptr+1);
 	    push_string(make_shared_binary_string("\0",1));
 	    o_multiply();
-	    /* FIXME: Wide strings? */
-	    env=(void *)Pike_sp[-1].u.string->str;
+
+	    /* NB: The environment string contains lots of NUL characters,
+	     *     so we must use the low-level variant here.
+	     */
+	    env = low_dwim_utf8_to_utf16(Pike_sp[-1].u.string->str,
+					 Pike_sp[-1].u.string->len);
+	    pop_stack();
 	  }
 	}
 
@@ -3031,26 +3037,31 @@ void f_create_process(INT32 args)
     THREADS_ALLOW_UID();
 
 
-    SetHandleInformation(info.hStdInput, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
-    SetHandleInformation(info.hStdOutput, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
-    SetHandleInformation(info.hStdError, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
-    ret=CreateProcess(filename,
-		      command_line,
-		      NULL,  /* process security attribute */
-		      NULL,  /* thread security attribute */
-		      1,     /* inherithandles */
-		      0,     /* create flags */
-		      env,  /* environment */
-		      dir,   /* current dir */
-		      &info,
-		      &proc);
+    SetHandleInformation(info.hStdInput, HANDLE_FLAG_INHERIT,
+			 HANDLE_FLAG_INHERIT);
+    SetHandleInformation(info.hStdOutput, HANDLE_FLAG_INHERIT,
+			 HANDLE_FLAG_INHERIT);
+    SetHandleInformation(info.hStdError, HANDLE_FLAG_INHERIT,
+			 HANDLE_FLAG_INHERIT);
+    ret = CreateProcessW(filename,
+			 command_line,
+			 NULL,  /* process security attribute */
+			 NULL,  /* thread security attribute */
+			 1,     /* inherithandles */
+			 CREATE_UNICODE_ENVIRONMENT,     /* create flags */
+			 env,  /* environment */
+			 dir,   /* current dir */
+			 &info,
+			 &proc);
     err=GetLastError();
     
     THREADS_DISALLOW_UID();
 
     UNLOCK_IMUTEX(&handle_protection_mutex);
 
-    if(env) pop_stack();
+    if(env) free(env);
+    if(dir) free(dir);
+    if(filename) free(filename);
     if(command_line) free(command_line);
 #if 1
     if(t1 != DO_NOT_WARN(INVALID_HANDLE_VALUE)) CloseHandle(t1);