diff --git a/src/libstd/sys/windows/c.rs b/src/libstd/sys/windows/c.rs
index c8f6aca7bd32e..a23379e6b3b2a 100644
--- a/src/libstd/sys/windows/c.rs
+++ b/src/libstd/sys/windows/c.rs
@@ -463,6 +463,10 @@ extern "system" {
                            nOutBufferSize: libc::DWORD,
                            lpBytesReturned: libc::LPDWORD,
                            lpOverlapped: libc::LPOVERLAPPED) -> libc::BOOL;
+    pub fn CreatePipe(hReadPipe: libc::LPHANDLE,
+                      hWritePipe: libc::LPHANDLE,
+                      lpPipeAttributes: libc::LPSECURITY_ATTRIBUTES,
+                      nSize: libc::DWORD) -> libc::BOOL;
 }
 
 #[link(name = "userenv")]
diff --git a/src/libstd/sys/windows/handle.rs b/src/libstd/sys/windows/handle.rs
index 0089dcad455df..c3a30aae9e0e8 100644
--- a/src/libstd/sys/windows/handle.rs
+++ b/src/libstd/sys/windows/handle.rs
@@ -36,11 +36,34 @@ impl Handle {
     }
 
     pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
-        read(self.0, buf)
+        let mut read = 0;
+        let res = cvt(unsafe {
+            libc::ReadFile(self.0, buf.as_ptr() as libc::LPVOID,
+                           buf.len() as libc::DWORD, &mut read,
+                           ptr::null_mut())
+        });
+
+        match res {
+            Ok(_) => Ok(read as usize),
+
+            // The special treatment of BrokenPipe is to deal with Windows
+            // pipe semantics, which yields this error when *reading* from
+            // a pipe after the other end has closed; we interpret that as
+            // EOF on the pipe.
+            Err(ref e) if e.kind() == ErrorKind::BrokenPipe => Ok(0),
+
+            Err(e) => Err(e)
+        }
     }
 
     pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
-        write(self.0, buf)
+        let mut amt = 0;
+        try!(cvt(unsafe {
+            libc::WriteFile(self.0, buf.as_ptr() as libc::LPVOID,
+                            buf.len() as libc::DWORD, &mut amt,
+                            ptr::null_mut())
+        }));
+        Ok(amt as usize)
     }
 }
 
@@ -49,35 +72,3 @@ impl Drop for Handle {
         unsafe { let _ = libc::CloseHandle(self.0); }
     }
 }
-
-
-pub fn read(h: HANDLE, buf: &mut [u8]) -> io::Result<usize> {
-    let mut read = 0;
-    let res = cvt(unsafe {
-        libc::ReadFile(h, buf.as_ptr() as libc::LPVOID,
-                       buf.len() as libc::DWORD, &mut read,
-                       ptr::null_mut())
-    });
-
-    match res {
-        Ok(_) => Ok(read as usize),
-
-        // The special treatment of BrokenPipe is to deal with Windows
-        // pipe semantics, which yields this error when *reading* from
-        // a pipe after the other end has closed; we interpret that as
-        // EOF on the pipe.
-        Err(ref e) if e.kind() == ErrorKind::BrokenPipe => Ok(0),
-
-        Err(e) => Err(e)
-    }
-}
-
-pub fn write(h: HANDLE, buf: &[u8]) -> io::Result<usize> {
-    let mut amt = 0;
-    try!(cvt(unsafe {
-        libc::WriteFile(h, buf.as_ptr() as libc::LPVOID,
-                        buf.len() as libc::DWORD, &mut amt,
-                        ptr::null_mut())
-    }));
-    Ok(amt as usize)
-}
diff --git a/src/libstd/sys/windows/pipe2.rs b/src/libstd/sys/windows/pipe2.rs
index ed41c95978289..b441d8beedbc0 100644
--- a/src/libstd/sys/windows/pipe2.rs
+++ b/src/libstd/sys/windows/pipe2.rs
@@ -10,70 +10,39 @@
 
 use prelude::v1::*;
 
-use sys::handle;
 use io;
-use libc::{self, c_int, HANDLE};
+use libc;
+use sys::cvt;
+use sys::c;
+use sys::handle::Handle;
 
 ////////////////////////////////////////////////////////////////////////////////
 // Anonymous pipes
 ////////////////////////////////////////////////////////////////////////////////
 
 pub struct AnonPipe {
-    fd: c_int
+    inner: Handle,
 }
 
 pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> {
-    // Windows pipes work subtly differently than unix pipes, and their
-    // inheritance has to be handled in a different way that I do not
-    // fully understand. Here we explicitly make the pipe non-inheritable,
-    // which means to pass it to a subprocess they need to be duplicated
-    // first, as in std::run.
-    let mut fds = [0; 2];
-    unsafe {
-        match libc::pipe(fds.as_mut_ptr(), 1024 as ::libc::c_uint,
-                         (libc::O_BINARY | libc::O_NOINHERIT) as c_int) {
-            0 => {
-                assert!(fds[0] != -1 && fds[0] != 0);
-                assert!(fds[1] != -1 && fds[1] != 0);
-
-                Ok((AnonPipe::from_fd(fds[0]), AnonPipe::from_fd(fds[1])))
-            }
-            _ => Err(io::Error::last_os_error()),
-        }
-    }
+    let mut reader = libc::INVALID_HANDLE_VALUE;
+    let mut writer = libc::INVALID_HANDLE_VALUE;
+    try!(cvt(unsafe {
+        c::CreatePipe(&mut reader, &mut writer, 0 as *mut _, 0)
+    }));
+    let reader = Handle::new(reader);
+    let writer = Handle::new(writer);
+    Ok((AnonPipe { inner: reader }, AnonPipe { inner: writer }))
 }
 
 impl AnonPipe {
-    pub fn from_fd(fd: libc::c_int) -> AnonPipe {
-        AnonPipe { fd: fd }
-    }
-
-    pub fn raw(&self) -> HANDLE {
-        unsafe { libc::get_osfhandle(self.fd) as libc::HANDLE }
-    }
+    pub fn handle(&self) -> &Handle { &self.inner }
 
     pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
-        handle::read(self.raw(), buf)
+        self.inner.read(buf)
     }
 
     pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
-        handle::write(self.raw(), buf)
-    }
-}
-
-impl Drop for AnonPipe {
-    fn drop(&mut self) {
-        // closing stdio file handles makes no sense, so never do it. Also, note
-        // that errors are ignored when closing a file descriptor. The reason
-        // for this is that if an error occurs we don't actually know if the
-        // file descriptor was closed or not, and if we retried (for something
-        // like EINTR), we might close another valid file descriptor (opened
-        // after we closed ours.
-        if self.fd > libc::STDERR_FILENO {
-            let n = unsafe { libc::close(self.fd) };
-            if n != 0 {
-                println!("error {} when closing file descriptor {}", n, self.fd);
-            }
-        }
+        self.inner.write(buf)
     }
 }
diff --git a/src/libstd/sys/windows/process2.rs b/src/libstd/sys/windows/process2.rs
index 7495392192170..fdb47eb8c8084 100644
--- a/src/libstd/sys/windows/process2.rs
+++ b/src/libstd/sys/windows/process2.rs
@@ -199,7 +199,7 @@ impl Process {
                         }
                     }
                     Stdio::Piped(ref pipe) => {
-                        let orig = pipe.raw();
+                        let orig = pipe.handle().raw();
                         if DuplicateHandle(cur_proc, orig, cur_proc, slot,
                                            0, TRUE, DUPLICATE_SAME_ACCESS) == FALSE {
                             return Err(Error::last_os_error())