initial implementation
diff --git a/Cargo.toml b/Cargo.toml
index 8d16b92..f065034 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -15,8 +15,12 @@
 version = "0.3"
 features = [
   "std",
+  "consoleapi",
+  "errhandlingapi",
   "fileapi",
   "minwindef",
   "processenv",
   "winbase",
+  "wincon",
+  "winerror",
 ]
diff --git a/src/console.rs b/src/console.rs
new file mode 100644
index 0000000..1f7dad8
--- /dev/null
+++ b/src/console.rs
@@ -0,0 +1,121 @@
+use std::io;
+use std::mem;
+
+use winapi::um::consoleapi::{GetConsoleMode, SetConsoleMode};
+use winapi::um::wincon::{
+    CONSOLE_SCREEN_BUFFER_INFO,
+    GetConsoleScreenBufferInfo, SetConsoleTextAttribute,
+};
+
+use AsHandleRef;
+
+/// Query the given handle for information about the console's screen buffer.
+///
+/// The given handle should represent a console. Otherwise, an error is
+/// returned.
+///
+/// This corresponds to calling [`GetConsoleScreenBufferInfo`].
+///
+/// [`GetConsoleScreenBufferInfo`]: https://docs.microsoft.com/en-us/windows/console/getconsolescreenbufferinfo
+pub fn screen_buffer_info<H: AsHandleRef>(
+    h: H,
+) -> io::Result<ScreenBufferInfo> {
+    unsafe {
+        let mut info: CONSOLE_SCREEN_BUFFER_INFO = mem::zeroed();
+        let rc = GetConsoleScreenBufferInfo(h.as_raw(), &mut info);
+        if rc == 0 {
+            return Err(io::Error::last_os_error());
+        }
+        Ok(ScreenBufferInfo(info))
+    }
+}
+
+/// Set the text attributes of the console represented by the given handle.
+///
+/// This corresponds to calling [`SetConsoleTextAttribute`].
+///
+/// [`SetConsoleTextAttribute`]: https://docs.microsoft.com/en-us/windows/console/setconsoletextattribute
+pub fn set_text_attributes<H: AsHandleRef>(
+    h: H,
+    attributes: u16,
+) -> io::Result<()> {
+    if unsafe { SetConsoleTextAttribute(h.as_raw(), attributes) } == 0 {
+        Err(io::Error::last_os_error())
+    } else {
+        Ok(())
+    }
+}
+
+/// Query the mode of the console represented by the given handle.
+///
+/// This corresponds to calling [`GetConsoleMode`], which describes the return
+/// value.
+///
+/// [`GetConsoleMode`]: https://docs.microsoft.com/en-us/windows/console/getconsolemode
+pub fn mode<H: AsHandleRef>(h: H) -> io::Result<u32> {
+    let mut mode = 0;
+    if unsafe { GetConsoleMode(h.as_raw(), &mut mode) } == 0 {
+        Err(io::Error::last_os_error())
+    } else {
+        Ok(mode)
+    }
+}
+
+/// Set the mode of the console represented by the given handle.
+///
+/// This corresponds to calling [`SetConsoleMode`], which describes the format
+/// of the mode parameter.
+///
+/// [`SetConsoleMode`]: https://docs.microsoft.com/en-us/windows/console/setconsolemode
+pub fn set_mode<H: AsHandleRef>(h: H, mode: u32) -> io::Result<()> {
+    if unsafe { SetConsoleMode(h.as_raw(), mode) } == 0 {
+        Err(io::Error::last_os_error())
+    } else {
+        Ok(())
+    }
+}
+
+/// Represents console screen buffer information such as size, cursor position
+/// and styling attributes.
+///
+/// This wraps a [`CONSOLE_SCREEN_BUFFER_INFO`].
+///
+/// [`CONSOLE_SCREEN_BUFFER_INFO`]: https://docs.microsoft.com/en-us/windows/console/console-screen-buffer-info-str
+#[derive(Clone)]
+pub struct ScreenBufferInfo(CONSOLE_SCREEN_BUFFER_INFO);
+
+impl ScreenBufferInfo {
+    /// Returns the size of the console screen buffer, in character columns and
+    /// rows.
+    ///
+    /// This corresponds to `dwSize`.
+    pub fn size(&self) -> (i16, i16) {
+        (self.0.dwSize.X, self.0.dwSize.Y)
+    }
+
+    /// Returns the position of the cursor in terms of column and row
+    /// coordinates of the console screen buffer.
+    ///
+    /// This corresponds to `dwCursorPosition`.
+    pub fn cursor_position(&self) -> (i16, i16) {
+        (self.0.dwCursorPosition.X, self.0.dwCursorPosition.Y)
+    }
+
+    /// Returns the character attributes associated with this console.
+    ///
+    /// This corresponds to `wAttributes`.
+    ///
+    /// See [`char info`] for more details.
+    ///
+    /// [`char info`]: https://docs.microsoft.com/en-us/windows/console/char-info-str
+    pub fn attributes(&self) -> u16 {
+        self.0.wAttributes
+    }
+
+    /// Returns the maximum size of the console window, in character columns
+    /// and rows, given the current screen buffer size and font and the screen
+    /// size.
+    pub fn max_window_size(&self) -> (i16, i16) {
+        (self.0.dwMaximumWindowSize.X, self.0.dwMaximumWindowSize.Y)
+    }
+}
diff --git a/src/file.rs b/src/file.rs
new file mode 100644
index 0000000..a9be91a
--- /dev/null
+++ b/src/file.rs
@@ -0,0 +1,158 @@
+use std::io;
+use std::mem;
+
+use winapi::shared::minwindef::FILETIME;
+use winapi::shared::winerror::NO_ERROR;
+use winapi::um::errhandlingapi::GetLastError;
+use winapi::um::fileapi::{
+    BY_HANDLE_FILE_INFORMATION,
+    GetFileInformationByHandle, GetFileType,
+};
+
+use AsHandleRef;
+
+/// Return various pieces of information about a file.
+///
+/// This includes information such as a file's size, unique identifier and
+/// time related fields.
+///
+/// This corresponds to calling [`GetFileInformationByHandle`].
+///
+/// [`GetFileInformationByHandle`]: https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-getfileinformationbyhandle
+pub fn information<H: AsHandleRef>(
+    h: H,
+) -> io::Result<Information> {
+    unsafe {
+        let mut info: BY_HANDLE_FILE_INFORMATION = mem::zeroed();
+        let rc = GetFileInformationByHandle(h.as_raw(), &mut info);
+        if rc == 0 {
+            return Err(io::Error::last_os_error());
+        };
+        Ok(Information(info))
+    }
+}
+
+/// Returns the file type of the given handle.
+///
+/// If there was a problem querying the file type, then an error is returned.
+///
+/// This corresponds to calling [`GetFileType`].
+///
+/// [`GetFileType`]: https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-getfiletype
+pub fn typ<H: AsHandleRef>(h: H) -> io::Result<Type> {
+    unsafe {
+        let rc = GetFileType(h.as_raw());
+        if rc == 0 && GetLastError() != NO_ERROR {
+            return Err(io::Error::last_os_error());
+        }
+        Ok(Type(rc))
+    }
+}
+
+/// Represents file information such as creation time, file size, etc.
+///
+/// This wraps a [`BY_HANDLE_FILE_INFORMATION`].
+///
+/// [`BY_HANDLE_FILE_INFORMATION`]: https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/ns-fileapi-_by_handle_file_information
+#[derive(Clone)]
+pub struct Information(BY_HANDLE_FILE_INFORMATION);
+
+impl Information {
+    /// Returns file attributes.
+    ///
+    /// This corresponds to `dwFileAttributes`.
+    pub fn file_attributes(&self) -> u64 {
+        self.0.dwFileAttributes as u64
+    }
+
+    /// Return the creation time, if one exists.
+    ///
+    /// This corresponds to `ftCreationTime`.
+    pub fn creation_time(&self) -> Option<u64> {
+        filetime_to_u64(self.0.ftCreationTime)
+    }
+
+    /// Return the last access time, if one exists.
+    ///
+    /// This corresponds to `ftLastAccessTime`.
+    pub fn last_access_time(&self) -> Option<u64> {
+        filetime_to_u64(self.0.ftLastAccessTime)
+    }
+
+    /// Return the last write time, if one exists.
+    ///
+    /// This corresponds to `ftLastWriteTime`.
+    pub fn last_write_time(&self) -> Option<u64> {
+        filetime_to_u64(self.0.ftLastWriteTime)
+    }
+
+    /// Return the serial number of the volume that the file is on.
+    ///
+    /// This corresponds to `dwVolumeSerialNumber`.
+    pub fn volume_serial_number(&self) -> u64 {
+        self.0.dwVolumeSerialNumber as u64
+    }
+
+    /// Return the file size, in bytes.
+    ///
+    /// This corresponds to `nFileSizeHigh` and `nFileSizeLow`.
+    pub fn file_size(&self) -> u64 {
+        ((self.0.nFileSizeHigh as u64) << 32) | (self.0.nFileSizeLow as u64)
+    }
+
+    /// Return the number of links to this file.
+    ///
+    /// This corresponds to `nNumberOfLinks`.
+    pub fn number_of_links(&self) -> u64 {
+        self.0.nNumberOfLinks as u64
+    }
+
+    /// Return the index of this file. The index of a file is a purpotedly
+    /// unique identifier for a file within a particular volume.
+    pub fn file_index(&self) -> u64 {
+        ((self.0.nFileIndexHigh as u64) << 32) | (self.0.nFileIndexLow as u64)
+    }
+}
+
+/// Represents a Windows file type.
+///
+/// This wraps the result of [`GetFileType`].
+///
+/// [`GetFileType`]: https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-getfiletype
+#[derive(Clone)]
+pub struct Type(u32);
+
+impl Type {
+    /// Returns true if this type represents a character file, which is
+    /// typically an LPT device or a console.
+    pub fn is_char(&self) -> bool {
+        self.0 == ::winapi::um::winbase::FILE_TYPE_CHAR
+    }
+
+    /// Returns true if this type represents a disk file.
+    pub fn is_disk(&self) -> bool {
+        self.0 == ::winapi::um::winbase::FILE_TYPE_DISK
+    }
+
+    /// Returns true if this type represents a sock, named pipe or an
+    /// anonymous pipe.
+    pub fn is_pipe(&self) -> bool {
+        self.0 == ::winapi::um::winbase::FILE_TYPE_PIPE
+    }
+
+    /// Returns true if this type is not known.
+    ///
+    /// Note that this never corresponds to a failure.
+    pub fn is_unknown(&self) -> bool {
+        self.0 == ::winapi::um::winbase::FILE_TYPE_UNKNOWN
+    }
+}
+
+fn filetime_to_u64(t: FILETIME) -> Option<u64> {
+    let v = ((t.dwHighDateTime as u64) << 32) | (t.dwLowDateTime as u64);
+    if v == 0 {
+        None
+    } else {
+        Some(v)
+    }
+}
diff --git a/src/lib.rs b/src/lib.rs
index 21c68ba..a2864e1 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,5 +1,20 @@
 /*!
-TODO.
+This crate provides a smattering of safe routines for parts of winapi. The
+primary purpose of this crate is to serve as a dumping ground for various
+utility functions that make interactions with winapi safe. This permits the
+centralization of `unsafe` when dealing with Windows APIs, and thus makes it
+easier to audit.
+
+A key abstraction in this crate is the combination of the
+[`Handle`](struct.Handle.html)
+and
+[`HandleRef`](struct.HandleRef.html)
+types. Both represent a valid Windows handle to an I/O-like object, where
+`Handle` is owned (the resource is closed when the handle is dropped) and
+`HandleRef` is borrowed (the resource is not closed when the handle is
+dropped). Many of the routines in this crate work on handles and accept
+anything that can be safely converted into a `HandleRef`. This includes
+standard library types such as `File`, `Stdin`, `Stdout` and `Stderr`.
 
 Note that this crate is completely empty on non-Windows platforms.
 */
@@ -10,5 +25,11 @@
 #[cfg(windows)]
 pub use win::*;
 
+/// Safe routines for dealing with the Windows console.
+#[cfg(windows)]
+pub mod console;
+/// Safe routines for dealing with files and handles on Windows.
+#[cfg(windows)]
+pub mod file;
 #[cfg(windows)]
 mod win;
diff --git a/src/win.rs b/src/win.rs
index e69de29..fd56e94 100644
--- a/src/win.rs
+++ b/src/win.rs
@@ -0,0 +1,241 @@
+use std::fs::File;
+use std::io;
+use std::os::windows::io::{
+    RawHandle,
+    AsRawHandle, FromRawHandle, IntoRawHandle,
+};
+use std::path::Path;
+use std::process;
+
+/// A handle represents an owned and valid Windows handle to a file-like
+/// object.
+///
+/// When an owned handle is dropped, then the underlying raw handle is closed.
+/// To get a borrowed handle, use `HandleRef`.
+#[derive(Debug)]
+pub struct Handle(File);
+
+impl AsRawHandle for Handle {
+    fn as_raw_handle(&self) -> RawHandle {
+        self.0.as_raw_handle()
+    }
+}
+
+impl FromRawHandle for Handle {
+    unsafe fn from_raw_handle(handle: RawHandle) -> Handle {
+        Handle(File::from_raw_handle(handle))
+    }
+}
+
+impl IntoRawHandle for Handle {
+    fn into_raw_handle(self) -> RawHandle {
+        self.0.into_raw_handle()
+    }
+}
+
+impl Handle {
+    /// Create an owned handle to the given file.
+    ///
+    /// When the returned handle is dropped, the file is closed.
+    ///
+    /// Note that if the given file represents a handle to a directory, then
+    /// it is generally required that it have been opened with the
+    /// [`FILE_FLAG_BACKUP_SEMANTICS`] flag in order to use it in various
+    /// calls such as `information` or `typ`. To have this done automatically
+    /// for you, use the `from_path_any` constructor.
+    ///
+    /// [`FILE_FLAG_BACKUP_SEMANTICS`]: https://docs.microsoft.com/en-us/windows/desktop/api/FileAPI/nf-fileapi-createfilea
+    pub fn from_file(file: File) -> Handle {
+        Handle(file)
+    }
+
+    /// Open a file to the given file path, and return an owned handle to that
+    /// file.
+    ///
+    /// When the returned handle is dropped, the file is closed.
+    ///
+    /// If there was a problem opening the file, then the corresponding error
+    /// is returned.
+    pub fn from_path<P: AsRef<Path>>(path: P) -> io::Result<Handle> {
+        Ok(Handle::from_file(File::open(path)?))
+    }
+
+    /// Like `from_path`, but supports opening directory handles as well.
+    ///
+    /// If you use `from_path` on a directory, then subsequent queries using
+    /// that handle will fail.
+    pub fn from_path_any<P: AsRef<Path>>(path: P) -> io::Result<Handle> {
+        use std::fs::OpenOptions;
+        use std::os::windows::fs::OpenOptionsExt;
+        use winapi::um::winbase::FILE_FLAG_BACKUP_SEMANTICS;
+
+        let file = OpenOptions::new()
+            .read(true)
+            .custom_flags(FILE_FLAG_BACKUP_SEMANTICS)
+            .open(path)?;
+        Ok(Handle::from_file(file))
+    }
+
+    /// Return this handle as a standard `File` reference.
+    pub fn as_file(&self) -> &File {
+        &self.0
+    }
+
+    /// Return this handle as a standard `File` mutable reference.
+    pub fn as_file_mut(&mut self) -> &mut File {
+        &mut self.0
+    }
+}
+
+/// Represents a borrowed and valid Windows handle to a file-like object, such
+/// as stdin/stdout/stderr or an actual file.
+///
+/// When a borrowed handle is dropped, then the underlying raw handle is
+/// **not** closed. To get an owned handle, use `Handle`.
+#[derive(Debug)]
+pub struct HandleRef(HandleRefInner);
+
+/// The representation of a HandleRef, on which we define a custom Drop impl
+/// that avoids closing the underlying raw handle.
+#[derive(Debug)]
+struct HandleRefInner(Option<File>);
+
+impl Drop for HandleRefInner {
+    fn drop(&mut self) {
+        self.0.take().unwrap().into_raw_handle();
+    }
+}
+
+impl AsRawHandle for HandleRef {
+    fn as_raw_handle(&self) -> RawHandle {
+        self.as_file().as_raw_handle()
+    }
+}
+
+impl Clone for HandleRef {
+    fn clone(&self) -> HandleRef {
+        unsafe { HandleRef::from_raw_handle(self.as_raw_handle()) }
+    }
+}
+
+impl HandleRef {
+    /// Create a borrowed handle to stdin.
+    ///
+    /// When the returned handle is dropped, stdin is not closed.
+    pub fn stdin() -> HandleRef {
+        unsafe { HandleRef::from_raw_handle(io::stdin().as_raw_handle()) }
+    }
+
+    /// Create a handle to stdout.
+    ///
+    /// When the returned handle is dropped, stdout is not closed.
+    pub fn stdout() -> HandleRef {
+        unsafe { HandleRef::from_raw_handle(io::stdout().as_raw_handle()) }
+    }
+
+    /// Create a handle to stderr.
+    ///
+    /// When the returned handle is dropped, stderr is not closed.
+    pub fn stderr() -> HandleRef {
+        unsafe { HandleRef::from_raw_handle(io::stderr().as_raw_handle()) }
+    }
+
+    /// Create a borrowed handle to the given file.
+    ///
+    /// When the returned handle is dropped, the file is not closed.
+    pub fn from_file(file: &File) -> HandleRef {
+        unsafe { HandleRef::from_raw_handle(file.as_raw_handle()) }
+    }
+
+    /// Create a borrowed handle from the given raw handle.
+    ///
+    /// Note that unlike the `FromRawHandle` trait, this constructor does
+    /// **not** consume ownership of the given handle. That is, when the
+    /// borrowed handle created by this constructor is dropped, the underlying
+    /// handle will not be closed.
+    ///
+    /// # Safety
+    ///
+    /// This is unsafe because there is no guarantee that the given raw handle
+    /// is a valid handle. The caller must ensure this is true before invoking
+    /// this constructor.
+    pub unsafe fn from_raw_handle(handle: RawHandle) -> HandleRef {
+        HandleRef(HandleRefInner(Some(File::from_raw_handle(handle))))
+    }
+
+    /// Return this handle as a standard `File` reference.
+    pub fn as_file(&self) -> &File {
+        (self.0).0.as_ref().unwrap()
+    }
+
+    /// Return this handle as a standard `File` mutable reference.
+    pub fn as_file_mut(&mut self) -> &mut File {
+        (self.0).0.as_mut().unwrap()
+    }
+}
+
+/// Construct borrowed and valid Windows handles from file-like objects.
+pub trait AsHandleRef {
+    /// A borrowed handle that wraps the raw handle of the `Self` object.
+    fn as_handle_ref(&self) -> HandleRef;
+
+    /// A convenience routine for extracting a `HandleRef` from `Self`, and
+    /// then extracting a raw handle from the `HandleRef`.
+    fn as_raw(&self) -> RawHandle {
+        self.as_handle_ref().as_raw_handle()
+    }
+}
+
+impl AsHandleRef for Handle {
+    fn as_handle_ref(&self) -> HandleRef {
+        unsafe { HandleRef::from_raw_handle(self.as_raw_handle()) }
+    }
+}
+
+impl AsHandleRef for HandleRef {
+    fn as_handle_ref(&self) -> HandleRef {
+        self.clone()
+    }
+}
+
+impl AsHandleRef for File {
+    fn as_handle_ref(&self) -> HandleRef {
+        HandleRef::from_file(self)
+    }
+}
+
+impl AsHandleRef for io::Stdin {
+    fn as_handle_ref(&self) -> HandleRef {
+        unsafe { HandleRef::from_raw_handle(self.as_raw_handle()) }
+    }
+}
+
+impl AsHandleRef for io::Stdout {
+    fn as_handle_ref(&self) -> HandleRef {
+        unsafe { HandleRef::from_raw_handle(self.as_raw_handle()) }
+    }
+}
+
+impl AsHandleRef for io::Stderr {
+    fn as_handle_ref(&self) -> HandleRef {
+        unsafe { HandleRef::from_raw_handle(self.as_raw_handle()) }
+    }
+}
+
+impl AsHandleRef for process::ChildStdin {
+    fn as_handle_ref(&self) -> HandleRef {
+        unsafe { HandleRef::from_raw_handle(self.as_raw_handle()) }
+    }
+}
+
+impl AsHandleRef for process::ChildStdout {
+    fn as_handle_ref(&self) -> HandleRef {
+        unsafe { HandleRef::from_raw_handle(self.as_raw_handle()) }
+    }
+}
+
+impl AsHandleRef for process::ChildStderr {
+    fn as_handle_ref(&self) -> HandleRef {
+        unsafe { HandleRef::from_raw_handle(self.as_raw_handle()) }
+    }
+}