diff --git a/CHANGELOG.markdown b/CHANGELOG.markdown
--- a/CHANGELOG.markdown
+++ b/CHANGELOG.markdown
@@ -1,3 +1,8 @@
+0.3.4
+=====
+
+  * Provided `hSize` on Windows. (https://github.com/biegunka/terminal-size/pull/18)
+
 0.3.3
 =====
 
diff --git a/README.markdown b/README.markdown
--- a/README.markdown
+++ b/README.markdown
@@ -1,7 +1,7 @@
 terminal-size
 =============
 
-[![Hackage](https://budueba.com/hackage/terminal-size)](https://hackage.haskell.org/package/terminal-size)
+[![Hackage](https://img.shields.io/hackage/v/terminal-size.svg?style=flat)](https://hackage.haskell.org/package/terminal-size)
 [![Build Status](https://travis-ci.org/biegunka/terminal-size.png)](https://travis-ci.org/biegunka/terminal-size)
 
 Get terminal window width and height
@@ -13,4 +13,45 @@
 >>> import System.Console.Terminal.Size
 >>> size
 Just (Window {height = 60, width = 112})
+```
+
+Test
+----
+
+Compile test.hs and run it in a terminal. Here is what I get on Linux:
+
+```
+> ghc test.hs
+> ./test
+With redirected stdin
+  hSize stdin = Nothing
+  hSize stdout = Just (Window {height = 19, width = 87})
+  hSize stderr = Just (Window {height = 19, width = 87})
+With redirected stdout
+  hSize stdin = Just (Window {height = 19, width = 87})
+  hSize stdout = Nothing
+  hSize stderr = Just (Window {height = 19, width = 87})
+With redirected stderr
+  hSize stdin = Just (Window {height = 19, width = 87})
+  hSize stdout = Just (Window {height = 19, width = 87})
+  hSize stderr = Nothing
+```
+
+On MINGW/MSYS the output is the same.
+
+On Windows with cmd.exe I get
+
+```
+With redirected stdin
+  hSize stdin = Nothing
+  hSize stdout = Just (Window {height = 40, width = 164})
+  hSize stderr = Just (Window {height = 40, width = 164})
+With redirected stdout
+  hSize stdin = Nothing
+  hSize stdout = Nothing
+  hSize stderr = Just (Window {height = 40, width = 164})
+With redirected stderr
+  hSize stdin = Nothing
+  hSize stdout = Just (Window {height = 40, width = 164})
+  hSize stderr = Nothing
 ```
diff --git a/src/System/Console/Terminal/Size.hs b/src/System/Console/Terminal/Size.hs
--- a/src/System/Console/Terminal/Size.hs
+++ b/src/System/Console/Terminal/Size.hs
@@ -9,8 +9,8 @@
   , size
 #if !defined(mingw32_HOST_OS)
   , fdSize
-  , hSize
 #endif
+  , hSize
   ) where
 
 import System.Console.Terminal.Common
@@ -19,8 +19,8 @@
 #else
 import qualified System.Console.Terminal.Posix as Host
 import System.Posix.Types(Fd)
-import System.IO(Handle)
 #endif
+import System.IO(Handle)
 
 
 -- | Get terminal window width and height for @stdout@.
@@ -45,14 +45,17 @@
 -- Nothing
 fdSize :: Integral n => Fd -> IO (Maybe (Window n))
 fdSize = Host.fdSize
+#endif
 
--- | /Not available on Windows:/
---   Same as 'fdSize', but takes 'Handle' instead of 'Fd' (file descriptor).
+-- | Same as 'fdSize', but takes 'Handle' instead of 'Fd' (file descriptor).
 --
+-- Note that on Windows with shells that use the native console API (cmd.exe,
+-- PowerShell) this works only for output handles like 'stdout' and 'stderr';
+-- for input handles like 'stdin' it always returns 'Nothing'.
+--
 -- >>> import System.Console.Terminal.Size
 -- >>> import System.IO
 -- >>> hSize stdout
 -- Just (Window {height = 56, width = 85})
 hSize :: Integral n => Handle -> IO (Maybe (Window n))
 hSize = Host.hSize
-#endif
diff --git a/src/System/Console/Terminal/Windows.hs b/src/System/Console/Terminal/Windows.hs
--- a/src/System/Console/Terminal/Windows.hs
+++ b/src/System/Console/Terminal/Windows.hs
@@ -1,63 +1,48 @@
-
-module System.Console.Terminal.Windows(size) where
+module System.Console.Terminal.Windows(size, hSize) where
 
 import System.Console.Terminal.Common
 
-import Control.Monad
-import Data.Word
-import Foreign.Ptr
-import Foreign.Storable
-import Foreign.Marshal.Alloc
 import System.Exit
 import System.IO
+import System.IO.Error (catchIOError)
 import System.Process
-
-type HANDLE = Ptr ()
-
-data CONSOLE_SCREEN_BUFFER_INFO
-
-sizeCONSOLE_SCREEN_BUFFER_INFO :: Int
-sizeCONSOLE_SCREEN_BUFFER_INFO = 22
-
-posCONSOLE_SCREEN_BUFFER_INFO_srWindow :: Int
-posCONSOLE_SCREEN_BUFFER_INFO_srWindow = 10 -- 4 x Word16 Left,Top,Right,Bottom
-
-c_STD_OUTPUT_HANDLE :: Word32
-c_STD_OUTPUT_HANDLE = -11
-
-foreign import stdcall unsafe "windows.h GetConsoleScreenBufferInfo"
-    c_GetConsoleScreenBufferInfo :: HANDLE -> Ptr CONSOLE_SCREEN_BUFFER_INFO -> IO Bool
+import System.Win32.Console
+  ( CONSOLE_SCREEN_BUFFER_INFO(srWindow)
+  , SMALL_RECT(..)
+  , getConsoleScreenBufferInfo
+  )
+import System.Win32.Types (HANDLE, withHandleToHANDLE)
 
-foreign import stdcall unsafe "windows.h GetStdHandle"
-    c_GetStdHandle :: Word32 -> IO HANDLE
+size :: Integral n => IO (Maybe (Window n))
+size = hSize stdout
 
+hSize :: Integral n => Handle -> IO (Maybe (Window n))
+hSize hdl =
+    withHandleToHANDLE hdl nativeSize
+    `catchIOError` \_ -> do
+        -- Fallback to use for Cygwin or MSYS
+        let stty = (shell "stty size") {
+              std_in  = UseHandle hdl
+            , std_out = CreatePipe
+            , std_err = CreatePipe
+            }
+        (_, mbStdout, _, rStty) <- createProcess stty
+        exStty <- waitForProcess rStty
+        case exStty of
+            ExitFailure _ -> return Nothing
+            ExitSuccess ->
+                maybe (return Nothing)
+                      (\out -> do
+                          sizeStr <- hGetContents out
+                          let [r, c] = map read $ words sizeStr :: [Int]
+                          return $ Just $ Window (fromIntegral r) (fromIntegral c)
+                      )
+                      mbStdout
 
-size :: Integral n => IO (Maybe (Window n))
-size = do
-    hdl <- c_GetStdHandle c_STD_OUTPUT_HANDLE
-    allocaBytes sizeCONSOLE_SCREEN_BUFFER_INFO $ \p -> do
-        b <- c_GetConsoleScreenBufferInfo hdl p
-        if not b
-            then do -- This could happen on Cygwin or MSYS
-                let stty = (shell "stty size") {
-                      std_in  = UseHandle stdin
-                    , std_out = CreatePipe
-                    , std_err = CreatePipe
-                    }
-                (_, mbStdout, _, rStty) <- createProcess stty
-                exStty <- waitForProcess rStty
-                case exStty of
-                    ExitFailure _ -> return Nothing
-                    ExitSuccess ->
-                        maybe (return Nothing)
-                              (\hSize -> do
-                                  sizeStr <- hGetContents hSize
-                                  let [r, c] = map read $ words sizeStr :: [Int]
-                                  return $ Just $ Window (fromIntegral r) (fromIntegral c)
-                              )
-                              mbStdout
-            else do
-                [left,top,right,bottom] <- forM [0..3] $ \i -> do
-                    v <- peekByteOff p ((i*2) + posCONSOLE_SCREEN_BUFFER_INFO_srWindow)
-                    return $ fromIntegral (v :: Word16)
-                return $ Just $ Window (1+bottom-top) (1+right-left)
+nativeSize :: Integral n => HANDLE -> IO (Maybe (Window n))
+nativeSize hdl = do
+    rect <- srWindow <$> getConsoleScreenBufferInfo hdl
+    return $ Just $ Window
+        { height = fromIntegral (1 + bottomPos rect - topPos rect)
+        , width = fromIntegral (1 + rightPos rect - leftPos rect)
+        }
diff --git a/terminal-size.cabal b/terminal-size.cabal
--- a/terminal-size.cabal
+++ b/terminal-size.cabal
@@ -1,5 +1,5 @@
 name:                terminal-size
-version:             0.3.3
+version:             0.3.4
 synopsis:            Get terminal window height and width
 description:
   Get terminal window height and width without ncurses dependency.
@@ -21,7 +21,7 @@
 source-repository this
   type:     git
   location: https://github.com/biegunka/terminal-size
-  tag:      0.3.3
+  tag:      0.3.4
 
 library
   default-language:
@@ -34,7 +34,8 @@
        ghc-prim
   if os(windows)
      build-depends:
-       process
+       process,
+       Win32 >= 2.13.2.0 && < 2.14
 
   build-tools:
     hsc2hs
